mirror of
https://github.com/apache/nifi.git
synced 2025-02-11 12:35:20 +00:00
NIFI-13329 - Updating the standard content viewer to render an error message when there is an error formatting.
Co-authored-by: Pierre Villard <pierre.villard.fr@gmail.com> Signed-off-by: Pierre Villard <pierre.villard.fr@gmail.com> This closes #8905.
This commit is contained in:
parent
a21c2544ad
commit
48edbeed90
@ -57,6 +57,7 @@
|
|||||||
<targetPath>WEB-INF/jsp</targetPath>
|
<targetPath>WEB-INF/jsp</targetPath>
|
||||||
<includes>
|
<includes>
|
||||||
<include>codemirror.jsp</include>
|
<include>codemirror.jsp</include>
|
||||||
|
<include>format-error.jsp</include>
|
||||||
</includes>
|
</includes>
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
|
@ -25,8 +25,9 @@ import org.apache.avro.generic.GenericData;
|
|||||||
import org.apache.avro.generic.GenericDatumReader;
|
import org.apache.avro.generic.GenericDatumReader;
|
||||||
import org.apache.avro.io.DatumReader;
|
import org.apache.avro.io.DatumReader;
|
||||||
import org.apache.nifi.web.ViewableContent.DisplayMode;
|
import org.apache.nifi.web.ViewableContent.DisplayMode;
|
||||||
import org.apache.nifi.xml.processing.ProcessingException;
|
|
||||||
import org.apache.nifi.xml.processing.transform.StandardTransformProvider;
|
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.DumperOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
@ -44,6 +45,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
public class StandardContentViewerController extends HttpServlet {
|
public class StandardContentViewerController extends HttpServlet {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(StandardContentViewerController.class);
|
||||||
|
|
||||||
private static final Set<String> supportedMimeTypes = new HashSet<>();
|
private static final Set<String> supportedMimeTypes = new HashSet<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -84,16 +87,15 @@ public class StandardContentViewerController extends HttpServlet {
|
|||||||
if (DisplayMode.Original.equals(content.getDisplayMode())) {
|
if (DisplayMode.Original.equals(content.getDisplayMode())) {
|
||||||
formatted = content.getContent();
|
formatted = content.getContent();
|
||||||
} else {
|
} else {
|
||||||
if ("application/json".equals(contentType)) {
|
try {
|
||||||
// format json
|
if ("application/json".equals(contentType)) {
|
||||||
final ObjectMapper mapper = new ObjectMapper();
|
// format json
|
||||||
final Object objectJson = mapper.readValue(content.getContentStream(), Object.class);
|
final ObjectMapper mapper = new ObjectMapper();
|
||||||
formatted = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectJson);
|
final Object objectJson = mapper.readValue(content.getContentStream(), Object.class);
|
||||||
} else if ("application/xml".equals(contentType) || "text/xml".equals(contentType)) {
|
formatted = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectJson);
|
||||||
// format xml
|
} else if ("application/xml".equals(contentType) || "text/xml".equals(contentType)) {
|
||||||
final StringWriter writer = new StringWriter();
|
// format xml
|
||||||
|
final StringWriter writer = new StringWriter();
|
||||||
try {
|
|
||||||
final StreamSource source = new StreamSource(content.getContentStream());
|
final StreamSource source = new StreamSource(content.getContentStream());
|
||||||
final StreamResult result = new StreamResult(writer);
|
final StreamResult result = new StreamResult(writer);
|
||||||
|
|
||||||
@ -101,67 +103,69 @@ public class StandardContentViewerController extends HttpServlet {
|
|||||||
transformProvider.setIndent(true);
|
transformProvider.setIndent(true);
|
||||||
|
|
||||||
transformProvider.transform(source, result);
|
transformProvider.transform(source, result);
|
||||||
} catch (final ProcessingException te) {
|
|
||||||
throw new IOException("Unable to transform content as XML: " + te, te);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the transformed xml
|
// get the transformed xml
|
||||||
formatted = writer.toString();
|
formatted = writer.toString();
|
||||||
} else if ("application/avro-binary".equals(contentType) || "avro/binary".equals(contentType) || "application/avro+binary".equals(contentType)) {
|
} else if ("application/avro-binary".equals(contentType) || "avro/binary".equals(contentType) || "application/avro+binary".equals(contentType)) {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
sb.append("[");
|
sb.append("[");
|
||||||
// Use Avro conversions to display logical type values in human readable way.
|
// Use Avro conversions to display logical type values in human readable way.
|
||||||
final GenericData genericData = new GenericData();
|
final GenericData genericData = new GenericData();
|
||||||
genericData.addLogicalTypeConversion(new Conversions.DecimalConversion());
|
genericData.addLogicalTypeConversion(new Conversions.DecimalConversion());
|
||||||
genericData.addLogicalTypeConversion(new TimeConversions.DateConversion());
|
genericData.addLogicalTypeConversion(new TimeConversions.DateConversion());
|
||||||
genericData.addLogicalTypeConversion(new TimeConversions.TimeMicrosConversion());
|
genericData.addLogicalTypeConversion(new TimeConversions.TimeMicrosConversion());
|
||||||
genericData.addLogicalTypeConversion(new TimeConversions.TimeMillisConversion());
|
genericData.addLogicalTypeConversion(new TimeConversions.TimeMillisConversion());
|
||||||
genericData.addLogicalTypeConversion(new TimeConversions.TimestampMicrosConversion());
|
genericData.addLogicalTypeConversion(new TimeConversions.TimestampMicrosConversion());
|
||||||
genericData.addLogicalTypeConversion(new TimeConversions.TimestampMillisConversion());
|
genericData.addLogicalTypeConversion(new TimeConversions.TimestampMillisConversion());
|
||||||
genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMicrosConversion());
|
genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMicrosConversion());
|
||||||
genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMillisConversion());
|
genericData.addLogicalTypeConversion(new TimeConversions.LocalTimestampMillisConversion());
|
||||||
final DatumReader<GenericData.Record> datumReader = new GenericDatumReader<>(null, null, genericData);
|
final DatumReader<GenericData.Record> datumReader = new GenericDatumReader<>(null, null, genericData);
|
||||||
try (final DataFileStream<GenericData.Record> dataFileReader = new DataFileStream<>(content.getContentStream(), datumReader)) {
|
try (final DataFileStream<GenericData.Record> dataFileReader = new DataFileStream<>(content.getContentStream(), datumReader)) {
|
||||||
while (dataFileReader.hasNext()) {
|
while (dataFileReader.hasNext()) {
|
||||||
final GenericData.Record record = dataFileReader.next();
|
final GenericData.Record record = dataFileReader.next();
|
||||||
final String formattedRecord = genericData.toString(record);
|
final String formattedRecord = genericData.toString(record);
|
||||||
sb.append(formattedRecord);
|
sb.append(formattedRecord);
|
||||||
sb.append(",");
|
sb.append(",");
|
||||||
// Do not format more than 10 MB of content.
|
// Do not format more than 10 MB of content.
|
||||||
if (sb.length() > 1024 * 1024 * 2) {
|
if (sb.length() > 1024 * 1024 * 2) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
} catch (final Throwable t) {
|
||||||
if (sb.length() > 1) {
|
logger.warn("Unable to format FlowFile content", t);
|
||||||
sb.deleteCharAt(sb.length() - 1);
|
this.getServletContext().getRequestDispatcher("/WEB-INF/jsp/format-error.jsp").include(request, response);
|
||||||
}
|
return;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
@ -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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user