NIFI-317:

- Adding support for exporting the lineage graph as SVG.
- Removing support to convert to PNG.
This commit is contained in:
Matt Gilman 2015-02-04 09:05:18 -05:00
parent b0b14ed10b
commit 4e85e34c31
4 changed files with 48 additions and 51 deletions

View File

@ -609,18 +609,6 @@
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>batik</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.6-1</version>
<exclusions>
<exclusion>
<groupId>fop</groupId>
<artifactId>fop</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>

View File

@ -16,34 +16,24 @@
*/ */
package org.apache.nifi.web.servlet; package org.apache.nifi.web.servlet;
import java.io.BufferedOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringReader;
import java.net.URLDecoder; import java.net.URLDecoder;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.util.XMLResourceDescriptor;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.svg.SVGDocument;
/** /**
* *
*/ */
@WebServlet(name = "ConvertSvg", urlPatterns = {"/convert-svg"}) @WebServlet(name = "DownloadSvg", urlPatterns = {"/download-svg"})
public class ConvertSvg extends HttpServlet { public class DownloadSvg extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(ConvertSvg.class); private static final Logger logger = LoggerFactory.getLogger(DownloadSvg.class);
/** /**
* *
@ -54,7 +44,6 @@ public class ConvertSvg extends HttpServlet {
*/ */
@Override @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final String uri = request.getRequestURL().toString();
final String rawSvg = request.getParameter("svg"); final String rawSvg = request.getParameter("svg");
// ensure the image markup has been included // ensure the image markup has been included
@ -69,7 +58,6 @@ public class ConvertSvg extends HttpServlet {
return; return;
} }
OutputStream bufferedOut = null;
try { try {
// get the svg and decode it, +'s need to be converted // get the svg and decode it, +'s need to be converted
final String svg = URLDecoder.decode(rawSvg.replace("+", "%2B"), "UTF-8"); final String svg = URLDecoder.decode(rawSvg.replace("+", "%2B"), "UTF-8");
@ -80,26 +68,16 @@ public class ConvertSvg extends HttpServlet {
String filename = request.getParameter("filename"); String filename = request.getParameter("filename");
if (filename == null) { if (filename == null) {
filename = "image.png"; filename = "image.svg";
} else if (!filename.endsWith(".png")) { } else if (!filename.endsWith(".svg")) {
filename += ".png"; filename += ".svg";
} }
final StringReader reader = new StringReader(svg); response.setContentType("image/svg+xml");
final String parser = XMLResourceDescriptor.getXMLParserClassName();
final SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
final SVGDocument doc = f.createSVGDocument(uri, reader);
response.setContentType("image/png");
response.setHeader("Content-Disposition", "attachment; filename=" + filename); response.setHeader("Content-Disposition", "attachment; filename=" + filename);
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
bufferedOut = new BufferedOutputStream(response.getOutputStream()); response.getWriter().print(svg);
final TranscoderInput transcoderInput = new TranscoderInput(doc);
final TranscoderOutput transcoderOutput = new TranscoderOutput(bufferedOut);
final PNGTranscoder transcoder = new PNGTranscoder();
transcoder.transcode(transcoderInput, transcoderOutput);
} catch (final Exception e) { } catch (final Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
@ -109,9 +87,7 @@ public class ConvertSvg extends HttpServlet {
// write the response message // write the response message
PrintWriter out = response.getWriter(); PrintWriter out = response.getWriter();
out.println("Unable to export image as a PNG."); out.println("Unable to export image as a SVG.");
} finally {
IOUtils.closeQuietly(bufferedOut);
} }
} }
} }

View File

@ -15,7 +15,9 @@
--> -->
<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"> <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</display-name> <display-name>nifi</display-name>
<!-- servlet to map to canvas page --> <!-- servlet to map to canvas page -->
<servlet> <servlet>
<servlet-name>NiFiCanvas</servlet-name> <servlet-name>NiFiCanvas</servlet-name>
<jsp-file>/WEB-INF/pages/canvas.jsp</jsp-file> <jsp-file>/WEB-INF/pages/canvas.jsp</jsp-file>
@ -24,7 +26,9 @@
<servlet-name>NiFiCanvas</servlet-name> <servlet-name>NiFiCanvas</servlet-name>
<url-pattern>/canvas</url-pattern> <url-pattern>/canvas</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to summary page --> <!-- servlet to map to summary page -->
<servlet> <servlet>
<servlet-name>NiFiSummary</servlet-name> <servlet-name>NiFiSummary</servlet-name>
<jsp-file>/WEB-INF/pages/summary.jsp</jsp-file> <jsp-file>/WEB-INF/pages/summary.jsp</jsp-file>
@ -33,7 +37,9 @@
<servlet-name>NiFiSummary</servlet-name> <servlet-name>NiFiSummary</servlet-name>
<url-pattern>/summary</url-pattern> <url-pattern>/summary</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to history page --> <!-- servlet to map to history page -->
<servlet> <servlet>
<servlet-name>NiFiHistory</servlet-name> <servlet-name>NiFiHistory</servlet-name>
<jsp-file>/WEB-INF/pages/history.jsp</jsp-file> <jsp-file>/WEB-INF/pages/history.jsp</jsp-file>
@ -42,7 +48,9 @@
<servlet-name>NiFiHistory</servlet-name> <servlet-name>NiFiHistory</servlet-name>
<url-pattern>/history</url-pattern> <url-pattern>/history</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to provenance page --> <!-- servlet to map to provenance page -->
<servlet> <servlet>
<servlet-name>NiFiProvenance</servlet-name> <servlet-name>NiFiProvenance</servlet-name>
<jsp-file>/WEB-INF/pages/provenance.jsp</jsp-file> <jsp-file>/WEB-INF/pages/provenance.jsp</jsp-file>
@ -51,7 +59,9 @@
<servlet-name>NiFiProvenance</servlet-name> <servlet-name>NiFiProvenance</servlet-name>
<url-pattern>/provenance</url-pattern> <url-pattern>/provenance</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to counters page --> <!-- servlet to map to counters page -->
<servlet> <servlet>
<servlet-name>NiFiCounters</servlet-name> <servlet-name>NiFiCounters</servlet-name>
<jsp-file>/WEB-INF/pages/counters.jsp</jsp-file> <jsp-file>/WEB-INF/pages/counters.jsp</jsp-file>
@ -60,7 +70,9 @@
<servlet-name>NiFiCounters</servlet-name> <servlet-name>NiFiCounters</servlet-name>
<url-pattern>/counters</url-pattern> <url-pattern>/counters</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to templates page --> <!-- servlet to map to templates page -->
<servlet> <servlet>
<servlet-name>NiFiTemplates</servlet-name> <servlet-name>NiFiTemplates</servlet-name>
<jsp-file>/WEB-INF/pages/templates.jsp</jsp-file> <jsp-file>/WEB-INF/pages/templates.jsp</jsp-file>
@ -69,7 +81,9 @@
<servlet-name>NiFiTemplates</servlet-name> <servlet-name>NiFiTemplates</servlet-name>
<url-pattern>/templates</url-pattern> <url-pattern>/templates</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to users page --> <!-- servlet to map to users page -->
<servlet> <servlet>
<servlet-name>NiFiUsers</servlet-name> <servlet-name>NiFiUsers</servlet-name>
<jsp-file>/WEB-INF/pages/users.jsp</jsp-file> <jsp-file>/WEB-INF/pages/users.jsp</jsp-file>
@ -78,7 +92,9 @@
<servlet-name>NiFiUsers</servlet-name> <servlet-name>NiFiUsers</servlet-name>
<url-pattern>/users</url-pattern> <url-pattern>/users</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to cluster page --> <!-- servlet to map to cluster page -->
<servlet> <servlet>
<servlet-name>NiFiCluster</servlet-name> <servlet-name>NiFiCluster</servlet-name>
<jsp-file>/WEB-INF/pages/cluster.jsp</jsp-file> <jsp-file>/WEB-INF/pages/cluster.jsp</jsp-file>
@ -87,7 +103,9 @@
<servlet-name>NiFiCluster</servlet-name> <servlet-name>NiFiCluster</servlet-name>
<url-pattern>/cluster</url-pattern> <url-pattern>/cluster</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to map to bulletin board page --> <!-- servlet to map to bulletin board page -->
<servlet> <servlet>
<servlet-name>BulletinBoard</servlet-name> <servlet-name>BulletinBoard</servlet-name>
<jsp-file>/WEB-INF/pages/bulletin-board.jsp</jsp-file> <jsp-file>/WEB-INF/pages/bulletin-board.jsp</jsp-file>
@ -96,15 +114,18 @@
<servlet-name>BulletinBoard</servlet-name> <servlet-name>BulletinBoard</servlet-name>
<url-pattern>/bulletin-board</url-pattern> <url-pattern>/bulletin-board</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to support image downloading --> <!-- servlet to support image downloading -->
<servlet> <servlet>
<servlet-name>ConvertSvg</servlet-name> <servlet-name>DownloadSvg</servlet-name>
<servlet-class>org.apache.nifi.web.servlet.ConvertSvg</servlet-class> <servlet-class>org.apache.nifi.web.servlet.DownloadSvg</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>ConvertSvg</servlet-name> <servlet-name>DownloadSvg</servlet-name>
<url-pattern>/convert-svg</url-pattern> <url-pattern>/download-svg</url-pattern>
</servlet-mapping> </servlet-mapping>
<filter> <filter>
<filter-name>IeEdgeHeader</filter-name> <filter-name>IeEdgeHeader</filter-name>
<filter-class>org.apache.nifi.web.filter.IeEdgeHeader</filter-class> <filter-class>org.apache.nifi.web.filter.IeEdgeHeader</filter-class>
@ -113,6 +134,7 @@
<filter-name>IeEdgeHeader</filter-name> <filter-name>IeEdgeHeader</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </filter-mapping>
<welcome-file-list> <welcome-file-list>
<welcome-file>canvas.jsp</welcome-file> <welcome-file>canvas.jsp</welcome-file>
<welcome-file>/WEB-INF/pages/canvas.jsp</welcome-file> <welcome-file>/WEB-INF/pages/canvas.jsp</welcome-file>

View File

@ -531,6 +531,10 @@ nf.ProvenanceLineage = (function () {
var svg = d3.select('#provenance-lineage-container').append('svg:svg') var svg = d3.select('#provenance-lineage-container').append('svg:svg')
.attr('width', width) .attr('width', width)
.attr('height', height) .attr('height', height)
.style({
'font-family': 'Verdana, Arial, sans-serif',
'font-size': '10px'
})
.call(lineageZoom) .call(lineageZoom)
.on('dblclick.zoom', null) .on('dblclick.zoom', null)
.on('mousedown', function (d) { .on('mousedown', function (d) {
@ -1276,7 +1280,14 @@ nf.ProvenanceLineage = (function () {
return '<g' + before + 'transform="translate(' + x + ',' + y + ')"' + after + '>'; return '<g' + before + 'transform="translate(' + x + ',' + y + ')"' + after + '>';
}); });
nf.Common.submit('POST', './convert-svg', { // namespaces
svg = svg.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"');
// doctype
svg = '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + svg;
// send to server to initiate download... client side only support is too browser specific at this point
nf.Common.submit('POST', './download-svg', {
'filename': 'provenance', 'filename': 'provenance',
'svg': encodeURIComponent(svg) 'svg': encodeURIComponent(svg)
}); });