You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by pv...@apache.org on 2024/06/03 17:35:53 UTC

(nifi) branch main updated: NIFI-13329 - Updating the standard content viewer to render an error message when there is an error formatting.

This is an automated email from the ASF dual-hosted git repository.

pvillard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 48edbeed90 NIFI-13329 - Updating the standard content viewer to render an error message when there is an error formatting.
48edbeed90 is described below

commit 48edbeed9066a564bfe6fffff80778f4b603c46a
Author: Matt Gilman <ma...@gmail.com>
AuthorDate: Fri May 31 14:29:26 2024 -0400

    NIFI-13329 - Updating the standard content viewer to render an error message when there is an error formatting.
    
    Co-authored-by: Pierre Villard <pi...@gmail.com>
    Signed-off-by: Pierre Villard <pi...@gmail.com>
    
    This closes #8905.
---
 .../nifi-standard-content-viewer/pom.xml           |   1 +
 .../nifi/web/StandardContentViewerController.java  | 138 +++++++++++----------
 .../src/main/webapp/WEB-INF/jsp/format-error.jsp   |  22 ++++
 .../src/main/webapp/css/main.css                   |  30 +++++
 4 files changed, 124 insertions(+), 67 deletions(-)

diff --git a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/pom.xml b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/pom.xml
index 02095ac086..6eec34603d 100644
--- a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/pom.xml
+++ b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/pom.xml
@@ -57,6 +57,7 @@
                             <targetPath>WEB-INF/jsp</targetPath>
                             <includes>
                                 <include>codemirror.jsp</include>
+                                <include>format-error.jsp</include>
                             </includes>
                             <filtering>true</filtering>
                         </resource>
diff --git a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/java/org/apache/nifi/web/StandardContentViewerController.java b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/java/org/apache/nifi/web/StandardContentViewerController.java
index e07d613713..e41ebec606 100644
--- a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/java/org/apache/nifi/web/StandardContentViewerController.java
+++ b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/java/org/apache/nifi/web/StandardContentViewerController.java
@@ -25,8 +25,9 @@ import org.apache.avro.generic.GenericData;
 import org.apache.avro.generic.GenericDatumReader;
 import org.apache.avro.io.DatumReader;
 import org.apache.nifi.web.ViewableContent.DisplayMode;
-import org.apache.nifi.xml.processing.ProcessingException;
 import org.apache.nifi.xml.processing.transform.StandardTransformProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.DumperOptions;
 import org.yaml.snakeyaml.Yaml;
 
@@ -44,6 +45,8 @@ import java.util.Set;
 
 public class StandardContentViewerController extends HttpServlet {
 
+    private static final Logger logger = LoggerFactory.getLogger(StandardContentViewerController.class);
+
     private static final Set<String> supportedMimeTypes = new HashSet<>();
 
     static {
@@ -84,16 +87,15 @@ public class StandardContentViewerController extends HttpServlet {
             if (DisplayMode.Original.equals(content.getDisplayMode())) {
                 formatted = content.getContent();
             } else {
-                if ("application/json".equals(contentType)) {
-                    // format json
-                    final ObjectMapper mapper = new ObjectMapper();
-                    final Object objectJson = mapper.readValue(content.getContentStream(), Object.class);
-                    formatted = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectJson);
-                } else if ("application/xml".equals(contentType) || "text/xml".equals(contentType)) {
-                    // format xml
-                    final StringWriter writer = new StringWriter();
-
-                    try {
+                try {
+                    if ("application/json".equals(contentType)) {
+                        // format json
+                        final ObjectMapper mapper = new ObjectMapper();
+                        final Object objectJson = mapper.readValue(content.getContentStream(), Object.class);
+                        formatted = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectJson);
+                    } else if ("application/xml".equals(contentType) || "text/xml".equals(contentType)) {
+                        // format xml
+                        final StringWriter writer = new StringWriter();
                         final StreamSource source = new StreamSource(content.getContentStream());
                         final StreamResult result = new StreamResult(writer);
 
@@ -101,67 +103,69 @@ public class StandardContentViewerController extends HttpServlet {
                         transformProvider.setIndent(true);
 
                         transformProvider.transform(source, result);
-                    } catch (final ProcessingException te) {
-                        throw new IOException("Unable to transform content as XML: " + te, te);
-                    }
 
-                    // get the transformed xml
-                    formatted = writer.toString();
-                } else if ("application/avro-binary".equals(contentType) || "avro/binary".equals(contentType) || "application/avro+binary".equals(contentType)) {
-                    final StringBuilder sb = new StringBuilder();
-                    sb.append("[");
-                    // Use Avro conversions to display logical type values in human readable way.
-                    final GenericData genericData = new GenericData();
-                    genericData.addLogicalTypeConversion(new Conversions.DecimalConversion());
-                    genericData.addLogicalTypeConversion(new TimeConversions.DateConversion());
-                    genericData.addLogicalTypeConversion(new TimeConversions.TimeMicrosConversion());
-                    genericData.addLogicalTypeConversion(new TimeConversions.TimeMillisConversion());
-                    genericData.addLogicalTypeConversion(new TimeConversions.TimestampMicrosConversion());
-                    genericData.addLogicalTypeConversion(new TimeConversions.TimestampMillisConversion());
-                    genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMicrosConversion());
-                    genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMillisConversion());
-                    final DatumReader<GenericData.Record> datumReader = new GenericDatumReader<>(null, null, genericData);
-                    try (final DataFileStream<GenericData.Record> dataFileReader = new DataFileStream<>(content.getContentStream(), datumReader)) {
-                        while (dataFileReader.hasNext()) {
-                            final GenericData.Record record = dataFileReader.next();
-                            final String formattedRecord = genericData.toString(record);
-                            sb.append(formattedRecord);
-                            sb.append(",");
-                            // Do not format more than 10 MB of content.
-                            if (sb.length() > 1024 * 1024 * 2) {
-                                break;
+                        // get the transformed xml
+                        formatted = writer.toString();
+                    } else if ("application/avro-binary".equals(contentType) || "avro/binary".equals(contentType) || "application/avro+binary".equals(contentType)) {
+                        final StringBuilder sb = new StringBuilder();
+                        sb.append("[");
+                        // Use Avro conversions to display logical type values in human readable way.
+                        final GenericData genericData = new GenericData();
+                        genericData.addLogicalTypeConversion(new Conversions.DecimalConversion());
+                        genericData.addLogicalTypeConversion(new TimeConversions.DateConversion());
+                        genericData.addLogicalTypeConversion(new TimeConversions.TimeMicrosConversion());
+                        genericData.addLogicalTypeConversion(new TimeConversions.TimeMillisConversion());
+                        genericData.addLogicalTypeConversion(new TimeConversions.TimestampMicrosConversion());
+                        genericData.addLogicalTypeConversion(new TimeConversions.TimestampMillisConversion());
+                        genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMicrosConversion());
+                        genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMillisConversion());
+                        final DatumReader<GenericData.Record> datumReader = new GenericDatumReader<>(null, null, genericData);
+                        try (final DataFileStream<GenericData.Record> dataFileReader = new DataFileStream<>(content.getContentStream(), datumReader)) {
+                            while (dataFileReader.hasNext()) {
+                                final GenericData.Record record = dataFileReader.next();
+                                final String formattedRecord = genericData.toString(record);
+                                sb.append(formattedRecord);
+                                sb.append(",");
+                                // Do not format more than 10 MB of content.
+                                if (sb.length() > 1024 * 1024 * 2) {
+                                    break;
+                                }
                             }
                         }
-                    }
 
-                    if (sb.length() > 1) {
-                        sb.deleteCharAt(sb.length() - 1);
+                        if (sb.length() > 1) {
+                            sb.deleteCharAt(sb.length() - 1);
+                        }
+                        sb.append("]");
+                        final String json = sb.toString();
+
+                        final ObjectMapper mapper = new ObjectMapper();
+                        final Object objectJson = mapper.readValue(json, Object.class);
+                        formatted = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectJson);
+
+                        contentType = "application/json";
+                    } else if ("text/x-yaml".equals(contentType) || "text/yaml".equals(contentType) || "text/yml".equals(contentType)
+                            || "application/x-yaml".equals(contentType) || "application/x-yml".equals(contentType)
+                            || "application/yaml".equals(contentType) || "application/yml".equals(contentType)) {
+                        Yaml yaml = new Yaml();
+                        // Parse the YAML file
+                        final Object yamlObject = yaml.load(content.getContentStream());
+                        DumperOptions options = new DumperOptions();
+                        options.setIndent(2);
+                        options.setPrettyFlow(true);
+                        // Fix below - additional configuration
+                        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+                        Yaml output = new Yaml(options);
+                        formatted = output.dump(yamlObject);
+
+                    } else {
+                        // leave plain text alone when formatting
+                        formatted = content.getContent();
                     }
-                    sb.append("]");
-                    final String json = sb.toString();
-
-                    final ObjectMapper mapper = new ObjectMapper();
-                    final Object objectJson = mapper.readValue(json, Object.class);
-                    formatted = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectJson);
-
-                    contentType = "application/json";
-                } else if ("text/x-yaml".equals(contentType) || "text/yaml".equals(contentType) || "text/yml".equals(contentType)
-                        || "application/x-yaml".equals(contentType) || "application/x-yml".equals(contentType)
-                        || "application/yaml".equals(contentType) || "application/yml".equals(contentType)) {
-                    Yaml yaml = new Yaml();
-                    // Parse the YAML file
-                    final Object yamlObject = yaml.load(content.getContentStream());
-                    DumperOptions options = new DumperOptions();
-                    options.setIndent(2);
-                    options.setPrettyFlow(true);
-                    // Fix below - additional configuration
-                    options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
-                    Yaml output = new Yaml(options);
-                    formatted = output.dump(yamlObject);
-
-                } else {
-                    // leave plain text alone when formatting
-                    formatted = content.getContent();
+                } catch (final Throwable t) {
+                    logger.warn("Unable to format FlowFile content", t);
+                    this.getServletContext().getRequestDispatcher("/WEB-INF/jsp/format-error.jsp").include(request, response);
+                    return;
                 }
             }
 
diff --git a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/webapp/WEB-INF/jsp/format-error.jsp b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/webapp/WEB-INF/jsp/format-error.jsp
new file mode 100644
index 0000000000..b91d657437
--- /dev/null
+++ b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/webapp/WEB-INF/jsp/format-error.jsp
@@ -0,0 +1,22 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<link rel="stylesheet" href="../${project.build.finalName}/css/main.css" type="text/css" />
+
+<div id="format-error">
+    Unable to format content. Please ensure the content type is correct (defined by the 'mime.type' attribute of the FlowFile).
+</div>
\ No newline at end of file
diff --git a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/webapp/css/main.css b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/webapp/css/main.css
new file mode 100644
index 0000000000..7aaa7e918a
--- /dev/null
+++ b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-content-viewer/src/main/webapp/css/main.css
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#format-error {
+    position: absolute;
+    right: 50px;
+    bottom: 50px;
+    left: 100px;
+    top: 104px;
+    border: 1px solid #aaa;
+    overflow: auto;
+    background-color: #fff;
+    font-style: italic;
+    padding: 5px;
+    font-size: 13px;
+}
\ No newline at end of file