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 <[email protected]>
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 <[email protected]>
    Signed-off-by: Pierre Villard <[email protected]>
    
    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

Reply via email to