mirror of https://github.com/apache/nifi.git
Squashed commit of the following:
commit 7e96bb903c4051613b5192e81aeaeef7997a9c1d Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 22 23:09:18 2015 -0400 Conflicts: nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateRegularExpression.java nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ExtractText.java commit 7fc79a34b7bee4b92988a36c64f8585b7fec8d33 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 22 22:40:51 2015 -0400 NIFI-353: - Only showing up to 1.5kb of the content in the hex view. commit 36f11c3d9d8466fa3f207b5fc859375b33370b53 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 22 16:27:19 2015 -0400 NIFI-353: - Disabling the content viewer by default. commit f78f74dc8dcc21e8f01ae65cb17a6db80c2f3a6c Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 22 16:24:45 2015 -0400 NIFI-353: - Adding error handling around the call into the content viewer extension. - Using forward instead of include when showing errors. commit b43fe6f935ce5697f551e5a3b30f7703b49f64a7 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 22 00:30:34 2015 -0400 NIFI-353: - Clean up. - Fixing authority check for DFM with check for Provenance. commit 61fc0467437a6fb0b9db4f1331699c23155aa3a6 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sat Mar 21 22:19:19 2015 -0400 NIFI-353: - Fixing artifact versions. commit 2bd1a18f3ca5258f745ddf4681f79ea2741aaa78 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Fri Mar 20 20:59:44 2015 -0400 NIFI-353: - Fixing artifact versions. commit c2eaa192eae7e977ffd50033a007693f636a6322 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Fri Mar 20 20:15:40 2015 -0400 NIFI-353: - Javadocs. - Updating the styles of the content labels. commit 3410197b7d88444de5c6f74622d67a1b0cc39e6a Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Fri Mar 20 19:40:02 2015 -0400 Squashed commit of the following: commite88ed13d8d
Merge:93b361e
3f36236
Author: Mark Payne <markap14@hotmail.com> Date: Fri Mar 20 09:11:39 2015 -0400 Merge branch 'inputstream-callback-protection' of https://github.com/rowolabi/incubator-nifi into develop commit93b361e69b
Merge:c9eb237
a6740a6
Author: Mark Payne <markap14@hotmail.com> Date: Thu Mar 19 11:49:11 2015 -0400 Merge branch 'develop' of http://git-wip-us.apache.org/repos/asf/incubator-nifi into develop commitc9eb237895
Author: Mark Payne <markap14@hotmail.com> Date: Thu Mar 19 11:40:01 2015 -0400 NIFI-443: Removed stopFunnel from ProcessGroup because we don't want to allow it commit8b911c5aab
Author: Mark Payne <markap14@hotmail.com> Date: Thu Mar 19 11:04:46 2015 -0400 NIFI-443: Always start funnels when added to process group, even when autoResumeState is false commita6740a6e2c
Author: joewitt <joewitt@apache.org> Date: Thu Mar 19 01:21:32 2015 -0400 NIFI-399 addressed items in the ticket commitad18853b58
Author: joewitt <joewitt@apache.org> Date: Wed Mar 18 10:59:13 2015 -0400 NIFI-399 initial port commit3f36236473
Author: Bobby Owolabi <bobbyowolabi@gmail.com> Date: Thu Mar 19 01:43:17 2015 -0400 NIFI-396 reverting accidentially modified whitespace in TestStandardProcessSession commitcd183be441
Author: Bobby Owolabi <bobbyowolabi@gmail.com> Date: Thu Mar 19 01:18:22 2015 -0400 NIFI-396 updated the javadocs of ProcessSession to reflect that a FlowFileAccessExcpetion will be thrown if an Input/Output Stream is attempted to be accessed after the callback is executed. commite2760f8c98
Author: Bobby Owolabi <bobbyowolabi@gmail.com> Date: Thu Mar 19 00:54:24 2015 -0400 NIFI-396 added a DisableOnCloseInputStream class; modified StandardProcessSession to prevent access of the Input/OutputStreams after callbacks have been executed; updated tests commit7272d0df58
Author: Bobby Owolabi <bobbyowolabi@gmail.com> Date: Wed Mar 18 23:30:57 2015 -0400 NIFI-396 created tests to demonstrate the situations where the ProcessSession throws an Exception and where it doesn't after it returns from the callback commiteb5ec703ba
Author: Oscar de la Pena <odelapena@exist.com> Date: Thu Mar 19 10:10:09 2015 +0800 Fixes incorrect messages count in Provenance reporter. Adds Unit test to verify fix commit b1873d86649d22fcf39956c93371be124a2e161b Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Wed Mar 18 23:08:57 2015 -0400 NIFI-353: - Adjusting the layout of the file name and content type. commit 0ebb54a501825cb68134f009c4810fb79e49c39f Merge: ecbccaedea9e22
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Wed Mar 18 21:23:37 2015 -0400 Merge branch 'develop' into NIFI-353 commit ecbccae7343561e25acc9383b64b8c155f2c5700 Merge: 4c448431cca300
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Tue Mar 17 23:20:39 2015 -0400 Merge branch 'develop' into NIFI-353 commit 4c448436c5f84ac5bd4b3afad1b75f40c45c6d54 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Tue Mar 17 23:20:24 2015 -0400 NIFI-353: - Modifying the hexview plugin to address html escape issues and no longer rendering the base64 padding characters. commit 1a05c9db63cbbe21e08b40a87da14526653c41e1 Author: joewitt <joewitt@apache.org> Date: Mon Mar 16 16:58:52 2015 -0400 NIFI-353 merged to latest dev post 002 release and fixed pom references. Viewer looks great commit 2b07b0bc1da9f4da6f40c31258c66afed30ffa4e Merge: f920902eb757a4
Author: joewitt <joewitt@apache.org> Date: Mon Mar 16 16:38:08 2015 -0400 Merge branch 'develop' into NIFI-353 commit f92090233fb3ad804cb1881d183592dfd30ffc99 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 15 23:51:31 2015 -0400 NIFI-353: - Addressing issues when running clustered. - Javadocs. commit 73a54eeb859fe9c8822141b59ee79eba8d1e6dff Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 15 09:16:24 2015 -0400 NIFI-353: - Adding support for text/plain. commit c117a5c6f16c173ba971097fb9a14e9ed495f25b Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 15 08:41:34 2015 -0400 NIFI-353: - Fixing dependency issue. - Setting the default content viewer path. - Restoring correct content type in the standard viewer META-INF. commit 12c867daea51d45b80767f82b1f8cf0ec249bb55 Merge: e7d77fecc890e2
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sat Mar 14 10:11:30 2015 -0400 Merge branch 'develop' into NIFI-353 commit e7d77fedbdac106803c553626050e380c8b51287 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Thu Mar 12 23:01:36 2015 -0400 NIFI-353 - Javadocs. - Cleaning up dependencies. commit a81e1ecbf85b34d5af2054b43118830f0d4fbfa3 Merge: 173177c7198912
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Thu Mar 12 21:40:45 2015 -0400 Merge branch 'develop' into NIFI-353 commit 173177c918e6c07c1c98d807ecc7f8be6d0fa637 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Wed Mar 11 23:21:43 2015 -0400 NIFI-353: - Cleaning up error handling. - Showing the file name and content type. commit 098f9709dc0cac7a475d21c08d72de839260952c Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Tue Mar 10 23:21:01 2015 -0400 NIFI-353: - Better error handling when unable to interpret the request, unable to find the content, and no viewer is registered for the detected content type. commit ee28e9de729dad477cc97b46d9a5e9cd9ef84609 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 8 22:57:15 2015 -0400 NIFI-353: - Replacing dependency on tika parsers with icu4j. commit a50a6b6e8bf393bb4d47672f69c13e1fa3bc202c Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 8 22:21:49 2015 -0400 NIFI-353: - Allowing the user to toggle between viewing the original content, the formatted content, and the raw bytes in a hex dump. commit d100a2839bb2aef5af0de00f5e78ecc9c7f1ad0a Merge: 347e4e0342ca17
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Mar 8 13:54:24 2015 -0400 Merge branch 'develop' into NIFI-353 commit 347e4e024d4e990e6eb17a2101c31db79200f7a7 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Thu Mar 5 23:20:39 2015 -0500 NIFI-353: - Updating markup generation flow. - Adding a combo box to view the content in original, formatted, or hex form (still not functional). commit 37b5ca48f43cd3bb80b080e14c7cc2478da859aa Merge: 48192285e0026c
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Wed Mar 4 21:44:10 2015 -0500 Merge branch 'develop' into NIFI-353 commit 48192289e492ed98bcc433925a70203570223c2a Merge: cc0b6fe50744bf
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Wed Feb 25 22:53:29 2015 -0500 Merge branch 'develop' into NIFI-353 commit cc0b6fe2f2b852457824357ff493b5c4e9d44ccd Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Wed Feb 25 22:50:23 2015 -0500 NIFI-353: - Starting to moving the hex viewer into the main content viewer web application that comes bundled in framework. Previously it was only in the standard content viewer extension but we want to be able to render the content in hex for all types of data. commit 60c411de0dab6e0dc099e9b1fb04adfb1c2507f1 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Tue Feb 24 23:15:21 2015 -0500 NIFI-353: - Starting to add support for the hex viewer. commit efe8e06827488b1156edd5ea65e712d2eb675ef2 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Feb 22 21:48:09 2015 -0500 NIFI-353: - Adding support for viewing xml documents. - Adding supporting to fold the json and xml documents. commit 1955926a857daede8091a761e984d22273ada235 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sat Feb 21 21:49:48 2015 -0500 NIFI-353: - Allowing the content to be obtained by either stream or as a string (with the char encoding detected using tika). - Set the json viewer size during window resize events. commit 43f6e3c0585436176527344febc860586ded3b60 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sat Feb 21 16:36:43 2015 -0500 NIFI-353: - Starting to add support for viewing JSON. - Updating codemirror to add support for JSON and XML. commit 8f54adf1c1e6cc581ee501d6f1182dac2ff63512 Merge: 605a05b57b5d58
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sat Feb 21 08:02:47 2015 -0500 Merge branch 'develop' into NIFI-353 commit 605a05b89f09bd16311d6321d6a1eeee881880b5 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Thu Feb 19 23:15:54 2015 -0500 NIFI-353: - Adding mime type detection using tika. commit bd9ef8431bc66f567d8e526e06f0635de2417254 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Wed Feb 18 23:35:28 2015 -0500 NIFI-353: - Continuing to wire up the content viewer controller to NiFi (standalone/clustered) and the content type specific renderer. commit 2334e4888e48764b93671b8ac2a00d26a07dc3bc Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Tue Feb 17 23:00:07 2015 -0500 NIFI-353: - Updating the mark up on the content page. commit 78bab591d1c717077c7ee975c5ab4cf17c02d139 Merge: b1b2eaf0047fa4
Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Tue Feb 17 22:48:33 2015 -0500 Merge branch 'develop' into NIFI-353 commit b1b2eafe807c8f2e6cccb1a51736db8badd5d03b Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Tue Feb 17 22:47:26 2015 -0500 NIFI-353: - Creating an interface for retrieving content. - Creating an interface for reading content bytes. - Integrating these concepts into the exiting content viewer controller. commit cd0a1bd42ac4b953cb1d8c979d7041373555882a Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Mon Feb 16 17:08:32 2015 -0500 NIFI-353: - Renaming data-viewer to content-viewer. commit 48b1572f177e2292ddbacc92a3a5838cc45c7a42 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Mon Feb 16 15:45:15 2015 -0500 NIFI-353: - Renaming data-viewer to content-viewer. commit b50953d9d22881bcdc34edf1a34557d975b6dcc7 Author: Matt Gilman <matt.c.gilman@gmail.com> Date: Sun Feb 15 18:20:17 2015 -0500 NIFI-353: - Starting to integrate the data viewer controller into the Jetty Server. - Starting to set up the data viewer controller. - Starting to set up the standard data viewer.
This commit is contained in:
parent
0bd27847ab
commit
e05c9fd20e
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Interface for obtaining content from the NiFi content repository.
|
||||
*/
|
||||
public interface ViewableContent {
|
||||
|
||||
public static final String CONTENT_REQUEST_ATTRIBUTE = "org.apache.nifi.web.content";
|
||||
|
||||
public enum DisplayMode {
|
||||
Original,
|
||||
Formatted,
|
||||
Hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* The stream to the viewable content. The data stream can only be read once so
|
||||
* an extension can call this method or getContent.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
InputStream getContentStream();
|
||||
|
||||
/**
|
||||
* Gets the content as a string. The data stream can only be read once so
|
||||
* an extension can call this method or getContentStream.
|
||||
*
|
||||
* @return
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
String getContent() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the desired play mode. If the mode is Hex the
|
||||
* framework will handle generating the mark up. The only
|
||||
* values that an extension will see is Original or Formatted.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
DisplayMode getDisplayMode();
|
||||
|
||||
/**
|
||||
* The contents file name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getFileName();
|
||||
|
||||
/**
|
||||
* The mime type of the content.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getContentType();
|
||||
}
|
|
@ -215,7 +215,6 @@
|
|||
<nifi.content.repository.always.sync>false</nifi.content.repository.always.sync>
|
||||
<nifi.content.viewer.url />
|
||||
|
||||
|
||||
<nifi.restore.directory />
|
||||
<nifi.ui.banner.text />
|
||||
<nifi.ui.autorefresh.interval>30 sec</nifi.ui.autorefresh.interval>
|
||||
|
|
|
@ -113,6 +113,11 @@
|
|||
<artifactId>nifi-client-dto</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-access</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-custom-ui-utilities</artifactId>
|
||||
|
@ -152,6 +157,11 @@
|
|||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-docs</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-viewer</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.apache.nifi.util.NiFiProperties;
|
|||
import org.apache.nifi.web.NiFiWebContext;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.web.ContentAccess;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
|
@ -99,7 +100,9 @@ public class JettyServer implements NiFiServer {
|
|||
private ExtensionMapping extensionMapping;
|
||||
private WebAppContext webApiContext;
|
||||
private WebAppContext webDocsContext;
|
||||
private WebAppContext webContentViewerContext;
|
||||
private Collection<WebAppContext> customUiWebContexts;
|
||||
private Collection<WebAppContext> contentViewerWebContexts;
|
||||
private final NiFiProperties props;
|
||||
|
||||
/**
|
||||
|
@ -164,6 +167,7 @@ public class JettyServer implements NiFiServer {
|
|||
File webApiWar = null;
|
||||
File webErrorWar = null;
|
||||
File webDocsWar = null;
|
||||
File webContentViewerWar = null;
|
||||
List<File> otherWars = new ArrayList<>();
|
||||
for (File war : warToNarWorkingDirectoryLookup.keySet()) {
|
||||
if (war.getName().toLowerCase().startsWith("nifi-web-api")) {
|
||||
|
@ -172,6 +176,8 @@ public class JettyServer implements NiFiServer {
|
|||
webErrorWar = war;
|
||||
} else if (war.getName().toLowerCase().startsWith("nifi-web-docs")) {
|
||||
webDocsWar = war;
|
||||
} else if (war.getName().toLowerCase().startsWith("nifi-web-content-viewer")) {
|
||||
webContentViewerWar = war;
|
||||
} else if (war.getName().toLowerCase().startsWith("nifi-web")) {
|
||||
webUiWar = war;
|
||||
} else {
|
||||
|
@ -188,23 +194,29 @@ public class JettyServer implements NiFiServer {
|
|||
throw new RuntimeException("Unable to load nifi-web-docs WAR");
|
||||
} else if (webErrorWar == null) {
|
||||
throw new RuntimeException("Unable to load nifi-web-error WAR");
|
||||
} else if (webContentViewerWar == null) {
|
||||
throw new RuntimeException("Unable to load nifi-web-content-viewer WAR");
|
||||
}
|
||||
|
||||
// handlers for each war and init params for the web api
|
||||
final HandlerCollection handlers = new HandlerCollection();
|
||||
final Map<String, String> initParams = new HashMap<>();
|
||||
final Map<String, String> customUiMappings = new HashMap<>();
|
||||
final Map<String, String> mimeTypeMappings = new HashMap<>();
|
||||
final ClassLoader frameworkClassLoader = getClass().getClassLoader();
|
||||
final ClassLoader jettyClassLoader = frameworkClassLoader.getParent();
|
||||
|
||||
// deploy the other wars
|
||||
if (CollectionUtils.isNotEmpty(otherWars)) {
|
||||
customUiWebContexts = new ArrayList<>();
|
||||
contentViewerWebContexts = new ArrayList<>();
|
||||
|
||||
for (File war : otherWars) {
|
||||
// see if this war is a custom processor ui
|
||||
List<String> customUiProcessorTypes = getCustomUiProcessorTypes(war);
|
||||
List<String> customUiProcessorTypes = getWarExtensions(war, "META-INF/nifi-processor");
|
||||
List<String> contentViewerMimeTypes = getWarExtensions(war, "META-INF/nifi-content-viewer");
|
||||
|
||||
// only include wars that are for custom processor ui's
|
||||
if (CollectionUtils.isNotEmpty(customUiProcessorTypes)) {
|
||||
// only include wars that are for extensions
|
||||
if (!customUiProcessorTypes.isEmpty() || !contentViewerMimeTypes.isEmpty()) {
|
||||
String warName = StringUtils.substringBeforeLast(war.getName(), ".");
|
||||
String warContextPath = String.format("/%s", warName);
|
||||
|
||||
|
@ -216,19 +228,27 @@ public class JettyServer implements NiFiServer {
|
|||
narClassLoaderForWar = jettyClassLoader;
|
||||
}
|
||||
|
||||
// create the custom ui web app context
|
||||
WebAppContext customUiContext = loadWar(war, warContextPath, narClassLoaderForWar);
|
||||
// create the extension web app context
|
||||
WebAppContext extensionUiContext = loadWar(war, warContextPath, narClassLoaderForWar);
|
||||
|
||||
// hold on to a reference to all custom ui web app contexts
|
||||
customUiWebContexts.add(customUiContext);
|
||||
// also store it by type so we can populate the appropriate initialization parameters
|
||||
if (!customUiProcessorTypes.isEmpty()) {
|
||||
customUiWebContexts.add(extensionUiContext);
|
||||
} else {
|
||||
// record the mime type to web app mapping (need to handle type collision)
|
||||
contentViewerWebContexts.add(extensionUiContext);
|
||||
}
|
||||
|
||||
// include custom ui web context in the handlers
|
||||
handlers.addHandler(customUiContext);
|
||||
handlers.addHandler(extensionUiContext);
|
||||
|
||||
// add the initialization paramters
|
||||
for (String customUiProcessorType : customUiProcessorTypes) {
|
||||
// map the processor type to the custom ui path
|
||||
initParams.put(customUiProcessorType, warContextPath);
|
||||
customUiMappings.put(customUiProcessorType, warContextPath);
|
||||
}
|
||||
for (final String contentViewerMimeType : contentViewerMimeTypes) {
|
||||
mimeTypeMappings.put(contentViewerMimeType, warContextPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,10 +259,14 @@ public class JettyServer implements NiFiServer {
|
|||
|
||||
// load the web api app
|
||||
webApiContext = loadWar(webApiWar, "/nifi-api", frameworkClassLoader);
|
||||
Map<String, String> webApiInitParams = webApiContext.getInitParams();
|
||||
webApiInitParams.putAll(initParams);
|
||||
webApiContext.getInitParams().putAll(customUiMappings);
|
||||
handlers.addHandler(webApiContext);
|
||||
|
||||
// load the content viewer app
|
||||
webContentViewerContext = loadWar(webContentViewerWar, "/nifi-content-viewer", frameworkClassLoader);
|
||||
webContentViewerContext.getInitParams().putAll(mimeTypeMappings);
|
||||
handlers.addHandler(webContentViewerContext);
|
||||
|
||||
// create a web app for the docs
|
||||
final String docsContextPath = "/nifi-docs";
|
||||
|
||||
|
@ -292,18 +316,18 @@ public class JettyServer implements NiFiServer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads the processor types that the specified war file is a custom UI for.
|
||||
* Returns the extension in the specified WAR using the specified path.
|
||||
*
|
||||
* @param warFile
|
||||
* @param war
|
||||
* @return
|
||||
*/
|
||||
private List<String> getCustomUiProcessorTypes(final File warFile) {
|
||||
private List<String> getWarExtensions(final File war, final String path) {
|
||||
List<String> processorTypes = new ArrayList<>();
|
||||
JarFile jarFile = null;
|
||||
try {
|
||||
// load the jar file and attempt to find the nifi-processor entry
|
||||
jarFile = new JarFile(warFile);
|
||||
JarEntry jarEntry = jarFile.getJarEntry("META-INF/nifi-processor");
|
||||
jarFile = new JarFile(war);
|
||||
JarEntry jarEntry = jarFile.getJarEntry(path);
|
||||
|
||||
// ensure the nifi-processor entry was found
|
||||
if (jarEntry != null) {
|
||||
|
@ -320,7 +344,7 @@ public class JettyServer implements NiFiServer {
|
|||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
logger.warn(String.format("Unable to inspect %s for a custom processor UI.", warFile));
|
||||
logger.warn(String.format("Unable to inspect %s for a custom processor UI.", war));
|
||||
} finally {
|
||||
try {
|
||||
// close the jar file - which closes all input streams obtained via getInputStream above
|
||||
|
@ -537,20 +561,48 @@ public class JettyServer implements NiFiServer {
|
|||
|
||||
// ensure the appropriate wars deployed successfully before injecting the NiFi context and security filters -
|
||||
// this must be done after starting the server (and ensuring there were no start up failures)
|
||||
if (webApiContext != null && CollectionUtils.isNotEmpty(customUiWebContexts)) {
|
||||
if (webApiContext != null) {
|
||||
final ServletContext webApiServletContext = webApiContext.getServletHandler().getServletContext();
|
||||
final WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(webApiServletContext);
|
||||
final NiFiWebContext NiFiWebContext = webApplicationContext.getBean("nifiWebContext", NiFiWebContext.class);
|
||||
|
||||
for (final WebAppContext customUiContext : customUiWebContexts) {
|
||||
// set the NiFi context in each custom ui servlet context
|
||||
final ServletContext customUiServletContext = customUiContext.getServletHandler().getServletContext();
|
||||
customUiServletContext.setAttribute("nifi-web-context", NiFiWebContext);
|
||||
if (CollectionUtils.isNotEmpty(customUiWebContexts)) {
|
||||
final NiFiWebContext niFiWebContext = webApplicationContext.getBean("nifiWebContext", NiFiWebContext.class);
|
||||
|
||||
for (final WebAppContext customUiContext : customUiWebContexts) {
|
||||
// set the NiFi context in each custom ui servlet context
|
||||
final ServletContext customUiServletContext = customUiContext.getServletHandler().getServletContext();
|
||||
customUiServletContext.setAttribute("nifi-web-context", niFiWebContext);
|
||||
|
||||
// add the security filter to any custom ui wars
|
||||
// add the security filter to any custom ui wars
|
||||
final FilterHolder securityFilter = webApiContext.getServletHandler().getFilter("springSecurityFilterChain");
|
||||
if (securityFilter != null) {
|
||||
customUiContext.addFilter(securityFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(contentViewerWebContexts)) {
|
||||
for (final WebAppContext contentViewerContext : contentViewerWebContexts) {
|
||||
// add the security filter to any content viewer wars
|
||||
final FilterHolder securityFilter = webApiContext.getServletHandler().getFilter("springSecurityFilterChain");
|
||||
if (securityFilter != null) {
|
||||
contentViewerContext.addFilter(securityFilter, "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the web content viewer war was loaded
|
||||
if (webContentViewerContext != null) {
|
||||
final ContentAccess contentAccess = webApplicationContext.getBean("contentAccess", ContentAccess.class);
|
||||
|
||||
// add the content access
|
||||
final ServletContext webContentViewerServletContext = webContentViewerContext.getServletHandler().getServletContext();
|
||||
webContentViewerServletContext.setAttribute("nifi-content-access", contentAccess);
|
||||
|
||||
// add the security filter to the content viewer controller
|
||||
final FilterHolder securityFilter = webApiContext.getServletHandler().getFilter("springSecurityFilterChain");
|
||||
if (securityFilter != null) {
|
||||
customUiContext.addFilter(securityFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
webContentViewerContext.addFilter(securityFilter, "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -560,7 +612,7 @@ public class JettyServer implements NiFiServer {
|
|||
final ServletContext webDocsServletContext = webDocsContext.getServletHandler().getServletContext();
|
||||
webDocsServletContext.setAttribute("nifi-extension-mapping", extensionMapping);
|
||||
}
|
||||
|
||||
|
||||
// if this nifi is a node in a cluster, start the flow service and load the flow - the
|
||||
// flow service is loaded here for clustered nodes because the loading of the flow will
|
||||
// initialize the connection between the node and the NCM. if the node connects (starts
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<artifactId>nifi-web-utils</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-access</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-client-dto</artifactId>
|
||||
|
|
|
@ -65,7 +65,6 @@ import org.apache.nifi.web.api.dto.status.ControllerStatusDTO;
|
|||
import org.apache.nifi.web.api.dto.status.NodeStatusDTO;
|
||||
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
|
||||
import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
|
||||
import org.apache.nifi.web.util.DownloadableContent;
|
||||
|
||||
/**
|
||||
* Defines the NiFiServiceFacade interface.
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import com.sun.jersey.api.client.ClientResponse;
|
||||
import com.sun.jersey.core.util.MultivaluedMapImpl;
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.cluster.manager.NodeResponse;
|
||||
import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
|
||||
import org.apache.nifi.cluster.manager.impl.WebClusterManager;
|
||||
import org.apache.nifi.cluster.node.Node;
|
||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||
import org.apache.nifi.controller.repository.claim.ContentDirection;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.security.user.NiFiUserDetails;
|
||||
import org.apache.nifi.web.util.WebUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class StandardNiFiContentAccess implements ContentAccess {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(StandardNiFiContentAccess.class);
|
||||
public static final String CLIENT_ID_PARAM = "clientId";
|
||||
|
||||
private NiFiProperties properties;
|
||||
private NiFiServiceFacade serviceFacade;
|
||||
private WebClusterManager clusterManager;
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasRole('ROLE_PROVENANCE')")
|
||||
public DownloadableContent getContent(final ContentRequestContext request) {
|
||||
// if clustered, send request to cluster manager
|
||||
if (properties.isClusterManager()) {
|
||||
// get the URI
|
||||
URI dataUri;
|
||||
try {
|
||||
dataUri = new URI(request.getDataUri());
|
||||
} catch (final URISyntaxException use) {
|
||||
throw new ClusterRequestException(use);
|
||||
}
|
||||
|
||||
// set the request parameters
|
||||
final MultivaluedMap<String, String> parameters = new MultivaluedMapImpl();
|
||||
parameters.add(CLIENT_ID_PARAM, request.getClientId());
|
||||
|
||||
// set the headers
|
||||
final Map<String, String> headers = new HashMap<>();
|
||||
if (StringUtils.isNotBlank(request.getProxiedEntitiesChain())) {
|
||||
headers.put("X-ProxiedEntitiesChain", request.getProxiedEntitiesChain());
|
||||
}
|
||||
|
||||
// add the user's authorities (if any) to the headers
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null) {
|
||||
final Object userDetailsObj = authentication.getPrincipal();
|
||||
if (userDetailsObj instanceof NiFiUserDetails) {
|
||||
// serialize user details object
|
||||
final String hexEncodedUserDetails = WebUtils.serializeObjectToHex((Serializable) userDetailsObj);
|
||||
|
||||
// put serialized user details in header
|
||||
headers.put("X-ProxiedEntityUserDetails", hexEncodedUserDetails);
|
||||
}
|
||||
}
|
||||
|
||||
// get the target node and ensure it exists
|
||||
final Node targetNode = clusterManager.getNode(request.getClusterNodeId());
|
||||
if (targetNode == null) {
|
||||
throw new UnknownNodeException("The specified cluster node does not exist.");
|
||||
}
|
||||
|
||||
final Set<NodeIdentifier> targetNodes = new HashSet<>();
|
||||
targetNodes.add(targetNode.getNodeId());
|
||||
|
||||
// replicate the request to the specific node
|
||||
final NodeResponse nodeResponse = clusterManager.applyRequest(HttpMethod.GET, dataUri, parameters, headers, targetNodes);
|
||||
final ClientResponse clientResponse = nodeResponse.getClientResponse();
|
||||
final MultivaluedMap<String, String> responseHeaders = clientResponse.getHeaders();
|
||||
|
||||
// get the file name
|
||||
final String contentDisposition = responseHeaders.getFirst("Content-Disposition");
|
||||
final String filename = StringUtils.substringAfterLast(contentDisposition, "filename=");
|
||||
|
||||
// get the content type
|
||||
final String contentType = responseHeaders.getFirst("Content-Type");
|
||||
|
||||
// create the downloadable content
|
||||
return new DownloadableContent(filename, contentType, clientResponse.getEntityInputStream());
|
||||
} else {
|
||||
// example URI: http://localhost:8080/nifi-api/controller/provenance/events/1/content/input
|
||||
final String eventDetails = StringUtils.substringAfterLast(request.getDataUri(), "events/");
|
||||
final String rawEventId = StringUtils.substringBefore(eventDetails, "/content/");
|
||||
final String rawDirection = StringUtils.substringAfterLast(eventDetails, "/content/");
|
||||
|
||||
// get the content type
|
||||
final Long eventId = Long.parseLong(rawEventId);
|
||||
final ContentDirection direction = ContentDirection.valueOf(rawDirection.toUpperCase());
|
||||
return serviceFacade.getContent(eventId, request.getDataUri(), direction);
|
||||
}
|
||||
}
|
||||
|
||||
public void setProperties(NiFiProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public void setServiceFacade(NiFiServiceFacade serviceFacade) {
|
||||
this.serviceFacade = serviceFacade;
|
||||
}
|
||||
|
||||
public void setClusterManager(WebClusterManager clusterManager) {
|
||||
this.clusterManager = clusterManager;
|
||||
}
|
||||
}
|
|
@ -16,8 +16,6 @@
|
|||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import org.apache.nifi.web.OptimisticLockingManager;
|
||||
import org.apache.nifi.web.ConfigurationSnapshot;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -150,7 +148,6 @@ import org.apache.nifi.web.dao.ProcessorDAO;
|
|||
import org.apache.nifi.web.dao.RemoteProcessGroupDAO;
|
||||
import org.apache.nifi.web.dao.SnippetDAO;
|
||||
import org.apache.nifi.web.dao.TemplateDAO;
|
||||
import org.apache.nifi.web.util.DownloadableContent;
|
||||
import org.apache.nifi.web.util.SnippetUtils;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
|
|
@ -89,7 +89,7 @@ public class StandardNiFiWebContext implements NiFiWebContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAnyRole('ROLE_DFM')")
|
||||
@PreAuthorize("hasRole('ROLE_DFM')")
|
||||
public void saveActions(final Collection<ProcessorConfigurationAction> processorActions) {
|
||||
Objects.requireNonNull(processorActions, "Actions cannot be null.");
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ import org.apache.nifi.web.api.request.ClientIdParameter;
|
|||
import org.apache.nifi.web.api.request.DateTimeParameter;
|
||||
import org.apache.nifi.web.api.request.IntegerParameter;
|
||||
import org.apache.nifi.web.api.request.LongParameter;
|
||||
import org.apache.nifi.web.util.DownloadableContent;
|
||||
import org.apache.nifi.web.DownloadableContent;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.codehaus.enunciate.jaxrs.TypeHint;
|
||||
|
|
|
@ -108,7 +108,7 @@ import org.apache.nifi.web.api.dto.search.SearchResultsDTO;
|
|||
import org.apache.nifi.web.api.dto.status.ControllerStatusDTO;
|
||||
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
|
||||
import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
|
||||
import org.apache.nifi.web.util.DownloadableContent;
|
||||
import org.apache.nifi.web.DownloadableContent;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.admin.service.UserService;
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
<bean class="org.apache.nifi.web.StandardOptimisticLockingManager" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<!-- content access -->
|
||||
<bean id="contentAccess" class="org.apache.nifi.web.StandardNiFiContentAccess">
|
||||
<property name="serviceFacade" ref="serviceFacade"/>
|
||||
<property name="properties" ref="nifiProperties"/>
|
||||
<property name="clusterManager" ref="clusterManager"/>
|
||||
</bean>
|
||||
|
||||
<!-- dto factory -->
|
||||
<bean id="dtoFactory" class="org.apache.nifi.web.api.dto.DtoFactory">
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web</artifactId>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-access</artifactId>
|
||||
</project>
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
/**
|
||||
* Provides access to content within NiFi.
|
||||
*
|
||||
* @author unattributed
|
||||
*/
|
||||
public interface ContentAccess {
|
||||
|
||||
/**
|
||||
* Gets the content for the specified claim.
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
DownloadableContent getContent(ContentRequestContext request);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
/**
|
||||
* A request for content.
|
||||
*/
|
||||
public interface ContentRequestContext {
|
||||
|
||||
/**
|
||||
* The URI to the data.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getDataUri();
|
||||
|
||||
/**
|
||||
* If clustered, this is the id of the node the data resides on.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getClusterNodeId();
|
||||
|
||||
/**
|
||||
* The client id for the user making the request.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getClientId();
|
||||
|
||||
/**
|
||||
* The proxy chain for the current request, if applicable.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getProxiedEntitiesChain();
|
||||
}
|
|
@ -14,12 +14,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.web.util;
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents content that can be downloaded.
|
||||
*/
|
||||
public final class DownloadableContent {
|
||||
|
||||
|
@ -33,14 +33,29 @@ public final class DownloadableContent {
|
|||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* The filename of the content.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* The content type of the content.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The content stream.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public InputStream getContent() {
|
||||
return content;
|
||||
}
|
1
nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/.gitignore
vendored
Executable file
1
nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/.gitignore
vendored
Executable file
|
@ -0,0 +1 @@
|
|||
/target
|
|
@ -0,0 +1,91 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web</artifactId>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-viewer</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-access</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-utils</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
<version>54.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>javax.servlet.jsp-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.el</groupId>
|
||||
<artifactId>javax.el-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp.jstl</groupId>
|
||||
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import com.ibm.icu.text.CharsetDetector;
|
||||
import com.ibm.icu.text.CharsetMatch;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.stream.io.StreamUtils;
|
||||
import org.apache.nifi.web.ViewableContent.DisplayMode;
|
||||
import org.apache.tika.detect.DefaultDetector;
|
||||
import org.apache.tika.io.TikaInputStream;
|
||||
import org.apache.tika.metadata.Metadata;
|
||||
import org.apache.tika.mime.MediaType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Controller servlet for viewing content. This is responsible for generating
|
||||
* the markup for the header and footer of the page. Included in that is the
|
||||
* combo that allows the user to choose how they wait to view the data
|
||||
* (original, formatted, hex). If a data viewer is registered for the detected
|
||||
* content type, it will include the markup it generates in the response.
|
||||
*/
|
||||
public class ContentViewerController extends HttpServlet {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ContentViewerController.class);
|
||||
|
||||
// 1.5kb - multiple of 12 (3 bytes = 4 base 64 encoded chars)
|
||||
private final static int BUFFER_LENGTH = 1536;
|
||||
|
||||
/**
|
||||
* Gets the content and defers to registered viewers to generate the markup.
|
||||
*
|
||||
* @param request servlet request
|
||||
* @param response servlet response
|
||||
* @throws ServletException if a servlet-specific error occurs
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
|
||||
// get the content
|
||||
final ServletContext servletContext = request.getServletContext();
|
||||
final ContentAccess contentAccess = (ContentAccess) servletContext.getAttribute("nifi-content-access");
|
||||
|
||||
// get the content
|
||||
final DownloadableContent downloadableContent;
|
||||
try {
|
||||
downloadableContent = contentAccess.getContent(getContentRequest(request));
|
||||
} catch (final ResourceNotFoundException rnfe) {
|
||||
request.setAttribute("title", "Error");
|
||||
request.setAttribute("messages", "Unable to find the specified content");
|
||||
|
||||
// forward to the error page
|
||||
final ServletContext viewerContext = servletContext.getContext("/nifi");
|
||||
viewerContext.getRequestDispatcher("/message").forward(request, response);
|
||||
return;
|
||||
} catch (final AccessDeniedException ade) {
|
||||
request.setAttribute("title", "Acess Denied");
|
||||
request.setAttribute("messages", "Unable to approve access to the specified content: " + ade.getMessage());
|
||||
|
||||
// forward to the error page
|
||||
final ServletContext viewerContext = servletContext.getContext("/nifi");
|
||||
viewerContext.getRequestDispatcher("/message").forward(request, response);
|
||||
return;
|
||||
} catch (final Exception e) {
|
||||
request.setAttribute("title", "Error");
|
||||
request.setAttribute("messages", "An unexcepted error has occurred: " + e.getMessage());
|
||||
|
||||
// forward to the error page
|
||||
final ServletContext viewerContext = servletContext.getContext("/nifi");
|
||||
viewerContext.getRequestDispatcher("/message").forward(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// determine how we want to view the data
|
||||
String mode = request.getParameter("mode");
|
||||
|
||||
// if the name isn't set, use original
|
||||
if (mode == null) {
|
||||
mode = DisplayMode.Original.name();
|
||||
}
|
||||
|
||||
// determine the display mode
|
||||
final DisplayMode displayMode;
|
||||
try {
|
||||
displayMode = DisplayMode.valueOf(mode);
|
||||
} catch (final IllegalArgumentException iae) {
|
||||
request.setAttribute("title", "Error");
|
||||
request.setAttribute("messages", "Invalid display mode: " + mode);
|
||||
|
||||
// forward to the error page
|
||||
final ServletContext viewerContext = servletContext.getContext("/nifi");
|
||||
viewerContext.getRequestDispatcher("/message").forward(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// buffer the content to support reseting in case we need to detect the content type or char encoding
|
||||
final BufferedInputStream bis = new BufferedInputStream(downloadableContent.getContent());
|
||||
|
||||
// detect the content type
|
||||
final DefaultDetector detector = new DefaultDetector();
|
||||
|
||||
// create the stream for tika to process, buffered to support reseting
|
||||
final TikaInputStream tikaStream = TikaInputStream.get(bis);
|
||||
|
||||
// provide a hint based on the filename
|
||||
final Metadata metadata = new Metadata();
|
||||
metadata.set(Metadata.RESOURCE_NAME_KEY, downloadableContent.getFilename());
|
||||
|
||||
// Get mime type
|
||||
final MediaType mediatype = detector.detect(tikaStream, metadata);
|
||||
final String mimeType = mediatype.toString();
|
||||
|
||||
// add attributes needed for the header
|
||||
final StringBuffer requestUrl = request.getRequestURL();
|
||||
request.setAttribute("requestUrl", requestUrl.toString());
|
||||
request.setAttribute("dataRef", request.getParameter("ref"));
|
||||
request.setAttribute("filename", downloadableContent.getFilename());
|
||||
request.setAttribute("contentType", mimeType);
|
||||
|
||||
// generate the header
|
||||
request.getRequestDispatcher("/WEB-INF/jsp/header.jsp").include(request, response);
|
||||
|
||||
// remove the attributes needed for the header
|
||||
request.removeAttribute("requestUrl");
|
||||
request.removeAttribute("dataRef");
|
||||
request.removeAttribute("filename");
|
||||
request.removeAttribute("contentType");
|
||||
|
||||
// generate the markup for the content based on the display mode
|
||||
if (DisplayMode.Hex.equals(displayMode)) {
|
||||
final byte[] buffer = new byte[BUFFER_LENGTH];
|
||||
final int read = StreamUtils.fillBuffer(bis, buffer, false);
|
||||
|
||||
// trim the byte array if necessary
|
||||
byte[] bytes = buffer;
|
||||
if (read != buffer.length) {
|
||||
bytes = new byte[read];
|
||||
System.arraycopy(buffer, 0, bytes, 0, read);
|
||||
}
|
||||
|
||||
// convert bytes into the base 64 bytes
|
||||
final String base64 = Base64.encodeBase64String(bytes);
|
||||
|
||||
// defer to the jsp
|
||||
request.setAttribute("content", base64);
|
||||
request.getRequestDispatcher("/WEB-INF/jsp/hexview.jsp").include(request, response);
|
||||
} else {
|
||||
// lookup a viewer for the content
|
||||
final String contentViewerUri = servletContext.getInitParameter(mimeType);
|
||||
|
||||
// handle no viewer for content type
|
||||
if (contentViewerUri == null) {
|
||||
request.getRequestDispatcher("/WEB-INF/jsp/no-viewer.jsp").include(request, response);
|
||||
} else {
|
||||
// create a request attribute for accessing the content
|
||||
request.setAttribute(ViewableContent.CONTENT_REQUEST_ATTRIBUTE, new ViewableContent() {
|
||||
@Override
|
||||
public InputStream getContentStream() {
|
||||
return bis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() throws IOException {
|
||||
// detect the charset
|
||||
final CharsetDetector detector = new CharsetDetector();
|
||||
detector.setText(bis);
|
||||
detector.enableInputFilter(true);
|
||||
final CharsetMatch match = detector.detect();
|
||||
|
||||
// ensure we were able to detect the charset
|
||||
if (match == null) {
|
||||
throw new IOException("Unable to detect character encoding.");
|
||||
}
|
||||
|
||||
// convert the stream using the detected charset
|
||||
return IOUtils.toString(bis, match.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewableContent.DisplayMode getDisplayMode() {
|
||||
return displayMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return downloadableContent.getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return mimeType;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
// generate the content
|
||||
final ServletContext viewerContext = servletContext.getContext(contentViewerUri);
|
||||
viewerContext.getRequestDispatcher("/view-content").include(request, response);
|
||||
} catch (final Exception e) {
|
||||
String message = e.getMessage() != null ? e.getMessage() : e.toString();
|
||||
message = "Unable to generate view of data: " + message;
|
||||
|
||||
// log the error
|
||||
logger.error(message);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.error(StringUtils.EMPTY, e);
|
||||
}
|
||||
|
||||
// populate the request attributes
|
||||
request.setAttribute("title", "Error");
|
||||
request.setAttribute("messages", message);
|
||||
|
||||
// forward to the error page
|
||||
final ServletContext viewerContext = servletContext.getContext("/nifi");
|
||||
viewerContext.getRequestDispatcher("/message").forward(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove the request attribute
|
||||
request.removeAttribute(ViewableContent.CONTENT_REQUEST_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
||||
// generate footer
|
||||
request.getRequestDispatcher("/WEB-INF/jsp/footer.jsp").include(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content request context based on the specified request.
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private ContentRequestContext getContentRequest(final HttpServletRequest request) {
|
||||
return new ContentRequestContext() {
|
||||
@Override
|
||||
public String getDataUri() {
|
||||
return request.getParameter("ref");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClusterNodeId() {
|
||||
final String ref = request.getParameter("ref");
|
||||
return StringUtils.substringAfterLast(ref, "clusterNodeId=");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return request.getParameter("clientId");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProxiedEntitiesChain() {
|
||||
return request.getHeader("X-ProxiedEntitiesChain");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
nifi-web-docs
|
||||
Copyright 2014-2015 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
===========================================
|
||||
Apache Software License v2
|
||||
===========================================
|
||||
|
||||
The following binary components are provided under the Apache Software License v2
|
||||
|
||||
(ASLv2) Apache Commons Lang
|
||||
The following NOTICE information applies:
|
||||
Apache Commons Lang
|
||||
Copyright 2001-2014 The Apache Software Foundation
|
||||
|
||||
This product includes software from the Spring Framework,
|
||||
under the Apache License 2.0 (see: StringUtils.containsWhitespace())
|
|
@ -0,0 +1,20 @@
|
|||
<%--
|
||||
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" %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,92 @@
|
|||
<%--
|
||||
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" %>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="shortcut icon" href="../nifi/images/nifi16.ico"/>
|
||||
<title>NiFi</title>
|
||||
<link href="css/main.css" rel="stylesheet" type="text/css" />
|
||||
<link href="../nifi/css/message-pane.css" rel="stylesheet" type="text/css" />
|
||||
<link href="../nifi/css/message-page.css" rel="stylesheet" type="text/css" />
|
||||
<link rel="stylesheet" href="../nifi/js/jquery/combo/jquery.combo.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../nifi/css/reset.css" type="text/css" />
|
||||
<script type="text/javascript" src="../nifi/js/jquery/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../nifi/js/jquery/combo/jquery.combo.js"></script>
|
||||
<script type="text/javascript">
|
||||
var $$ = $.noConflict(true);
|
||||
$$(document).ready(function () {
|
||||
var url = '${requestUrl}';
|
||||
var ref = '${param.ref}';
|
||||
|
||||
// create the parameters
|
||||
var params = {
|
||||
ref: ref
|
||||
};
|
||||
|
||||
// include the cluster node if appropriate
|
||||
var clusterNodeId = '${param.clusterNodeId}';
|
||||
if (clusterNodeId !== null && clusterNodeId !== '') {
|
||||
params['clusterNodeId'] = clusterNodeId;
|
||||
}
|
||||
|
||||
// determine the appropriate mode to select initially
|
||||
var initialMode = '${param.mode}';
|
||||
if (initialMode === null && initialMode === '') {
|
||||
initialMode = 'Original';
|
||||
}
|
||||
|
||||
var currentLocation = null;
|
||||
$$('#view-as').combo({
|
||||
options: [{
|
||||
text: 'original',
|
||||
value: 'Original'
|
||||
}, {
|
||||
text: 'formatted',
|
||||
value: 'Formatted'
|
||||
}, {
|
||||
text: 'hex',
|
||||
value: 'Hex'
|
||||
}],
|
||||
selectedOption: {
|
||||
value: initialMode
|
||||
},
|
||||
select: function (option) {
|
||||
// just record the selection during creation
|
||||
if (currentLocation === null) {
|
||||
currentLocation = option.value;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the selection has changesd, reload the page
|
||||
if (currentLocation !== option.value) {
|
||||
window.location.href = url + '?' + $$.param($$.extend({
|
||||
mode: option.value
|
||||
}, params));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body class="message-pane">
|
||||
<div id="view-as-label">View as</div>
|
||||
<div id="view-as" class="pointer button-normal"></div>
|
||||
<div id="content-filename"><span class="content-label">filename</span>${filename}</div>
|
||||
<div id="content-type"><span class="content-label">content type</span>${contentType}</div>
|
||||
<div class="message-pane-message-box">
|
|
@ -0,0 +1,32 @@
|
|||
<%--
|
||||
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="js/hexview/hexview.default.css" type="text/css" />
|
||||
<script type="text/javascript" src="../nifi/js/jquery/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="js/hexview/hexview.js"></script>
|
||||
|
||||
<div id="hexview-content" class="hexviewwindow" title="">
|
||||
${content}
|
||||
<form id="hexviewwindow_params">
|
||||
<input type="hidden" name="highlights" value="" />
|
||||
<input type="hidden" name="row_width" value="16" />
|
||||
<input type="hidden" name="word_size" value="1" />
|
||||
<input type="hidden" name="hide_0x" value="1" />
|
||||
<input type="hidden" name="caption" value="" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="trancation-message">Showing up to 1.5kb</div>
|
|
@ -0,0 +1,20 @@
|
|||
<%--
|
||||
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" %>
|
||||
<div id="no-viewer">
|
||||
No viewer is registered for this content type.
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
|
||||
<display-name>nifi-content-viewer</display-name>
|
||||
<servlet>
|
||||
<servlet-name>ContentViewerController</servlet-name>
|
||||
<servlet-class>org.apache.nifi.web.ContentViewerController</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ContentViewerController</servlet-name>
|
||||
<url-pattern></url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app>
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#view-as-label {
|
||||
position: absolute;
|
||||
top: 72px;
|
||||
left: 144px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#view-as {
|
||||
position: absolute;
|
||||
top: 72px;
|
||||
left: 200px;
|
||||
width: 80px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
#content-filename {
|
||||
position: absolute;
|
||||
top: 58px;
|
||||
right: 50px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#content-type {
|
||||
position: absolute;
|
||||
top: 75px;
|
||||
right: 50px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.content-label {
|
||||
font-weight: bold;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* hex viewer */
|
||||
|
||||
#hexview-content {
|
||||
position: absolute;
|
||||
right: 50px;
|
||||
bottom: 50px;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
border: 1px solid #aaa;
|
||||
overflow: auto;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#hexview-content table.hexviewerwindow_table {
|
||||
border: none;
|
||||
margin-left: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#hexview-content td {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#trancation-message {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
bottom: 35px;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* no viewer */
|
||||
|
||||
#no-viewer {
|
||||
position: absolute;
|
||||
right: 50px;
|
||||
bottom: 50px;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
border: 1px solid #aaa;
|
||||
overflow: auto;
|
||||
background-color: #fff;
|
||||
font-style: italic;
|
||||
padding: 5px;
|
||||
font-size: 13px;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
HexViewJS License
|
||||
-----------------
|
||||
|
||||
HexViewJS is written by Nick McVeity <nmcveity@gmail.com> and is
|
||||
licensed under the terms of the MIT license reproduced below.
|
||||
|
||||
========================================================================
|
||||
|
||||
Copyright (c) 2010 Nick McVeity <nmcveity@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
========================================================================
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
.hexviewerwindow { font-family: monospace; background-color: #F2F2F2;}
|
||||
div.hexviewerwindow { padding: 20px; }
|
||||
.hexviewerwindow_table { border-collapse:collapse; border: 5px solid grey; margin-left: 16px; caption-side:bottom; }
|
||||
.hexviewerwindow_offset {background: #A9D0F5; padding-right: 8px; }
|
||||
.hexviewerwindow_visual {background: #A9F5F2; padding-left: 8px; }
|
||||
.hexviewerwindow_code {}
|
||||
.hexviewerwindow_code_hi {background: #F4FA58; }
|
||||
.hexviewerwindow_border_start {border-left: solid #E0E0E0 1px; }
|
||||
.hexviewerwindow_border_middle {border-bottom: solid #E0E0E0 1px; border-top: solid #E0E0E0 1px;}
|
||||
.hexviewerwindow_border_end {border-right: solid #E0E0E0 1px; border-top: solid #E0E0E0 1px; }
|
|
@ -0,0 +1,199 @@
|
|||
$(document).ready(function () {
|
||||
var HEX = '0123456789ABCDEF';
|
||||
|
||||
function dec2_to_hex(dec)
|
||||
{
|
||||
if (dec < 0)
|
||||
dec = 0;
|
||||
|
||||
if (dec > 255)
|
||||
dec = 255;
|
||||
|
||||
return HEX.charAt(Math.floor(dec / 16)) + HEX.charAt(dec % 16);
|
||||
}
|
||||
|
||||
function dec_to_hex8(dec)
|
||||
{
|
||||
var str = "";
|
||||
|
||||
for (var i = 3; i >= 0; i--)
|
||||
{
|
||||
str += dec2_to_hex((dec >> (i*8)) & 255);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
function remove_whitespace(str)
|
||||
{
|
||||
return str.replace(/\n/g, "")
|
||||
.replace(/\t/g, "")
|
||||
.replace(/ /g, "")
|
||||
.replace(/\r/g, "");
|
||||
}
|
||||
|
||||
var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
function base64_decode(encoded)
|
||||
{
|
||||
var decoded = "";
|
||||
|
||||
for (var i = 0; i < encoded.length; i += 4)
|
||||
{
|
||||
var ch0 = encoded.charAt(i+0);
|
||||
var ch1 = encoded.charAt(i+1);
|
||||
var ch2 = encoded.charAt(i+2);
|
||||
var ch3 = encoded.charAt(i+3);
|
||||
|
||||
var index0 = BASE64_CHARS.indexOf(ch0);
|
||||
var index1 = BASE64_CHARS.indexOf(ch1);
|
||||
var index2 = BASE64_CHARS.indexOf(ch2);
|
||||
var index3 = BASE64_CHARS.indexOf(ch3);
|
||||
|
||||
decoded += String.fromCharCode((index0 << 2) | (index1 >> 4));
|
||||
decoded += String.fromCharCode(((index1 & 15) << 4) | (index2 >> 2));
|
||||
|
||||
// skip the base64 padding as those weren't present in the actual bytes
|
||||
var token = String.fromCharCode(((index2 & 3) << 6) | index3);
|
||||
if (index3 !== 64 || token !== '@') {
|
||||
decoded += token;
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
function markup_hexviewwindow(div, index)
|
||||
{
|
||||
var entityMap = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/'
|
||||
};
|
||||
|
||||
function escapeHtml(string) {
|
||||
if (string === null || typeof string === 'undefined') {
|
||||
return '';
|
||||
} else {
|
||||
return String(string).replace(/[&<>"'\/]/g, function (s) {
|
||||
return entityMap[s];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var bin_data = base64_decode(remove_whitespace(div.text()));
|
||||
var line_data;
|
||||
var title = div.attr("title");
|
||||
|
||||
var highlights_str = $("form#hexviewwindow_params input[name='highlights']", div).attr("value").split(',');
|
||||
var highlights = [];
|
||||
|
||||
for (var i = 0; i < highlights_str.length; i++)
|
||||
{
|
||||
highlights.push(highlights_str[i].split(":"));
|
||||
}
|
||||
|
||||
var params = title.split(':');
|
||||
var step = parseInt($("form#hexviewwindow_params input[name='row_width']", div).attr("value"));
|
||||
var word_size = parseInt($("form#hexviewwindow_params input[name='word_size']", div).attr("value"));
|
||||
var hide_0x = parseInt($("form#hexviewwindow_params input[name='hide_0x']", div).attr("value"));
|
||||
var decimal_offset = parseInt($("form#hexviewwindow_params input[name='decimal_offset']", div).attr("value"));
|
||||
var start_byte_1 = parseInt($("form#hexviewwindow_params input[name='start_byte_1']", div).attr("value"));
|
||||
var caption = $("form#hexviewwindow_params input[name='caption']", div).attr("value");
|
||||
|
||||
div.text("");
|
||||
div.append("<table></table>");
|
||||
|
||||
var offset = (start_byte_1 ? 1 : 0);
|
||||
|
||||
function apply_highlights(index)
|
||||
{
|
||||
for (var j = 0; j < highlights.length; j++)
|
||||
{
|
||||
if ((index >= highlights[j][0]) && (index <= highlights[j][1]))
|
||||
{
|
||||
if (index === highlights[j][0])
|
||||
{
|
||||
$("table tr td:last", div).addClass("hexviewerwindow_border_start");
|
||||
}
|
||||
|
||||
if (index === highlights[j][1])
|
||||
{
|
||||
$("table tr td:last", div).addClass("hexviewerwindow_border_end");
|
||||
}
|
||||
|
||||
$("table tr td:last", div).addClass("hexviewerwindow_code_hi hexviewerwindow_border_middle");
|
||||
$("table tr td:last", div).attr("style", "background-color: " + highlights[j][2] + ";");
|
||||
$("table tr td:last", div).attr("title", highlights[j][3]);
|
||||
|
||||
runlen += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$("table tr td:last", div).addClass("hexviewerwindow_code");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (caption)
|
||||
$("table", div).append("<caption>" + escapeHtml(caption) + "</caption>");
|
||||
|
||||
while (bin_data.length > 0)
|
||||
{
|
||||
line_data = bin_data.slice(0, step);
|
||||
bin_data = bin_data.slice(step);
|
||||
|
||||
$("table", div).addClass("hexviewerwindow_table");
|
||||
$("table", div).append("<tr></tr>").addClass("hexviewerwindow");
|
||||
$("table tr:last", div).append("<td>" + (decimal_offset ? ("00000000"+offset).slice(-8) : "0x" + dec_to_hex8(offset)) + "</td>");
|
||||
$("table tr td:last", div).addClass("hexviewerwindow_offset");
|
||||
|
||||
var runlen = 0;
|
||||
|
||||
for (var i = 0; i < line_data.length; i += word_size)
|
||||
{
|
||||
var num = "";
|
||||
|
||||
for (var j = 0; j < word_size; j++)
|
||||
{
|
||||
num += dec2_to_hex(line_data.charCodeAt(i+j));
|
||||
}
|
||||
|
||||
$("table tr:last", div).append("<td>" + (hide_0x ? "" : "0x") + num + "</td>");
|
||||
|
||||
apply_highlights(offset+i);
|
||||
}
|
||||
|
||||
var text = "";
|
||||
|
||||
for (var i = 0; i < line_data.length; i++)
|
||||
{
|
||||
var cc = line_data.charCodeAt(i);
|
||||
|
||||
if ((cc >= 32) && (cc <= 126))
|
||||
{
|
||||
text = text + line_data.charAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text + ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (line_data.length < step)
|
||||
$("table tr td:last", div).attr("colspan", Math.floor((step - line_data.length) / word_size) + 1);
|
||||
|
||||
offset += step;
|
||||
|
||||
$("table tr:last", div).append("<td>" + escapeHtml(text) + "</td>");
|
||||
$("table tr td:last", div).addClass("hexviewerwindow_visual");
|
||||
}
|
||||
}
|
||||
|
||||
$("div.hexviewwindow").each(function (index) {
|
||||
markup_hexviewwindow($(this), index);
|
||||
});
|
||||
});
|
|
@ -115,6 +115,17 @@
|
|||
<url-pattern>/bulletin-board</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- servlet to support message page -->
|
||||
|
||||
<servlet>
|
||||
<servlet-name>MessagePage</servlet-name>
|
||||
<jsp-file>/WEB-INF/pages/message-page.jsp</jsp-file>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>MessagePage</servlet-name>
|
||||
<url-pattern>/message</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- servlet to support image downloading -->
|
||||
|
||||
<servlet>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
.CodeMirror-foldmarker {
|
||||
color: blue;
|
||||
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
|
||||
font-family: arial;
|
||||
line-height: .3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter {
|
||||
width: .7em;
|
||||
}
|
||||
.CodeMirror-foldgutter-open,
|
||||
.CodeMirror-foldgutter-folded {
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter-open:after {
|
||||
content: "\25BE";
|
||||
}
|
||||
.CodeMirror-foldgutter-folded:after {
|
||||
content: "\25B8";
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -86,3 +86,11 @@ div.combo-nifi-tooltip {
|
|||
background-color: #FFFFA3;
|
||||
color: #454545;
|
||||
}
|
||||
|
||||
div.button-normal {
|
||||
background: transparent url(../../../images/bgButton.png) repeat-x center center;
|
||||
}
|
||||
|
||||
div.button-over {
|
||||
background: transparent url(../../../images/bgButtonOver.png) repeat-x center center;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,10 @@
|
|||
<module>nifi-web-api</module>
|
||||
<module>nifi-web-error</module>
|
||||
<module>nifi-web-docs</module>
|
||||
<module>nifi-web-content-viewer</module>
|
||||
<module>nifi-web-ui</module>
|
||||
<module>nifi-jetty</module>
|
||||
<module>nifi-web-content-access</module>
|
||||
</modules>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
@ -52,6 +54,12 @@
|
|||
<type>war</type>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-viewer</artifactId>
|
||||
<type>war</type>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-ui</artifactId>
|
||||
|
|
|
@ -63,6 +63,11 @@
|
|||
<artifactId>nifi-client-dto</artifactId>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-web-content-access</artifactId>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-security</artifactId>
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-standard-bundle</artifactId>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-standard-content-viewer</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<version>1.9.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>javax.servlet.jsp-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.el</groupId>
|
||||
<artifactId>javax.el-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp.jstl</groupId>
|
||||
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.TransformerFactoryConfigurationError;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import org.apache.nifi.web.ViewableContent.DisplayMode;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@WebServlet(name = "StandardContentViewer", urlPatterns = {"/view-content"})
|
||||
public class StandardContentViewerController extends HttpServlet {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param request servlet request
|
||||
* @param response servlet response
|
||||
* @throws ServletException if a servlet-specific error occurs
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
final ViewableContent content = (ViewableContent) request.getAttribute(ViewableContent.CONTENT_REQUEST_ATTRIBUTE);
|
||||
|
||||
// handle json/xml
|
||||
if ("application/json".equals(content.getContentType()) || "application/xml".equals(content.getContentType()) || "text/plain".equals(content.getContentType())) {
|
||||
final String formatted;
|
||||
|
||||
// leave the content alone if specified
|
||||
if (DisplayMode.Original.equals(content.getDisplayMode())) {
|
||||
formatted = content.getContent();
|
||||
} else {
|
||||
if ("application/json".equals(content.getContentType())) {
|
||||
// format json
|
||||
final ObjectMapper mapper = new ObjectMapper();
|
||||
final Object objectJson = mapper.readValue(content.getContent(), Object.class);
|
||||
formatted = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectJson);
|
||||
} else if ("application/xml".equals(content.getContentType())) {
|
||||
// format xml
|
||||
final StringWriter writer = new StringWriter();
|
||||
|
||||
try {
|
||||
final StreamSource source = new StreamSource(content.getContentStream());
|
||||
final StreamResult result = new StreamResult(writer);
|
||||
|
||||
final TransformerFactory transformFactory = TransformerFactory.newInstance();
|
||||
final Transformer transformer = transformFactory.newTransformer();
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
|
||||
transformer.transform(source, result);
|
||||
} catch (final TransformerFactoryConfigurationError | TransformerException te) {
|
||||
throw new IOException("Unable to transform content as XML: " + te, te);
|
||||
}
|
||||
|
||||
// get the transformed xml
|
||||
formatted = writer.toString();
|
||||
} else {
|
||||
// leave plain text alone when formatting
|
||||
formatted = content.getContent();
|
||||
}
|
||||
}
|
||||
|
||||
// defer to the jsp
|
||||
request.setAttribute("mode", content.getContentType());
|
||||
request.setAttribute("content", formatted);
|
||||
request.getRequestDispatcher("/WEB-INF/jsp/codemirror.jsp").include(request, response);
|
||||
} else {
|
||||
final PrintWriter out = response.getWriter();
|
||||
out.println("Unexpected content type: " + content.getContentType());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
nifi-web-docs
|
||||
Copyright 2014-2015 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
===========================================
|
||||
Apache Software License v2
|
||||
===========================================
|
||||
|
||||
The following binary components are provided under the Apache Software License v2
|
||||
|
||||
(ASLv2) Apache Commons Lang
|
||||
The following NOTICE information applies:
|
||||
Apache Commons Lang
|
||||
Copyright 2001-2014 The Apache Software Foundation
|
||||
|
||||
This product includes software from the Spring Framework,
|
||||
under the Apache License 2.0 (see: StringUtils.containsWhitespace())
|
|
@ -0,0 +1,3 @@
|
|||
application/xml
|
||||
application/json
|
||||
text/plain
|
|
@ -0,0 +1,47 @@
|
|||
<%--
|
||||
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="../nifi/js/codemirror/lib/codemirror.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../nifi/js/codemirror/addon/fold/foldgutter.css" type="text/css" />
|
||||
<script type="text/javascript" src="../nifi/js/codemirror/lib/codemirror-compressed.js"></script>
|
||||
<script type="text/javascript" src="../nifi/js/jquery/jquery-2.1.1.min.js"></script>
|
||||
|
||||
<textarea id="codemirror-content">${content}</textarea>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var field = document.getElementById('codemirror-content');
|
||||
var editor = CodeMirror.fromTextArea(field, {
|
||||
mode: '${mode}',
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
foldGutter: true,
|
||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
|
||||
readOnly: true
|
||||
});
|
||||
|
||||
var setEditorSize = function() {
|
||||
editor.setSize($(window).width() - 150, $(window).height() - 150);
|
||||
};
|
||||
|
||||
// reset the editor size when the window changes
|
||||
$(window).resize(setEditorSize);
|
||||
|
||||
// initialize the editor size
|
||||
setEditorSize();
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
|
||||
<display-name>nifi-standard-content-viewer</display-name>
|
||||
<servlet>
|
||||
<servlet-name>StandardContentViewer</servlet-name>
|
||||
<servlet-class>org.apache.nifi.web.StandardContentViewerController</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>StandardContentViewer</servlet-name>
|
||||
<url-pattern>/view-content</url-pattern>
|
||||
</servlet-mapping>
|
||||
<welcome-file-list>
|
||||
<welcome-file>view-content</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
|
@ -40,5 +40,10 @@
|
|||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-standard-reporting-tasks</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-standard-content-viewer</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
|
@ -26,8 +27,9 @@
|
|||
<module>nifi-standard-processors</module>
|
||||
<module>nifi-standard-prioritizers</module>
|
||||
<module>nifi-standard-reporting-tasks</module>
|
||||
<module>nifi-standard-content-viewer</module>
|
||||
<module>nifi-standard-nar</module>
|
||||
</modules>
|
||||
</modules>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -45,6 +47,12 @@
|
|||
<artifactId>nifi-standard-reporting-tasks</artifactId>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-standard-content-viewer</artifactId>
|
||||
<type>war</type>
|
||||
<version>0.1.0-incubating-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
Loading…
Reference in New Issue