Annotation of java/classes/org/w3c/rdf/examples/ARPServlet.java, revision 1.19
1.16 barstow 1: /***********************************************************************
2: *
3: * ARPServlet - this servlet implements an RDF Validation service. As
4: * of this writing, the following RDF validation service used this
5: * servlet:
6: *
7: * http://www.w3.org/RDF/Validator/
8: *
9: ***********************************************************************
1.1 barstow 10: *
11: * Copyright © World Wide Web Consortium, (Massachusetts Institute of
12: * Technology, Institut National de Recherche en Informatique et en
13: * Automatique, Keio University).
14: *
15: * All Rights Reserved.
16: *
17: * Please see the full Copyright clause at
18: * <http://www.w3.org/Consortium/Legal/copyright-software.html>
19: *
1.16 barstow 20: ***********************************************************************
21: *
22: * This servlet is a wrapper for the ARP RDF parser. See the following
23: * for information about the ARP RDF parser:
24: *
25: * http://www.hpl.hp.co.uk/people/jjc/arp/
26: *
27: ***********************************************************************
28: *
29: * Implementation notes:
30: *
31: * o This servlet supports the HTTP POST operation; it does not
32: * support the HTTP GET operation
33: *
34: * o Depending upon the parameters given to the servlet it may
35: * invoke a GraphViz suprocess to generate a graph of the RDF.
36: * See the following for more information about GraphViz:
1.1 barstow 37: *
1.16 barstow 38: * http://www.research.att.com/sw/tools/graphviz/
1.1 barstow 39: *
1.16 barstow 40: * The servlet assumes version 1.7.4 of GraphViz.
1.1 barstow 41: *
1.16 barstow 42: * o Depending upon the parameters given to the servlet, the RDF
43: * to be validated may be copied to a file. The name of the file
44: * is automatically generated via Java's temporary file APIs. The
45: * location of the directory where the file is stored is configured
46: * via the serverlet's init() method. See below for more information.
47: *
48: * o See the section on Server Initialization for more information.
49: *
50: ***********************************************************************
51: *
52: * HTTP POST parameters - the servlet expects/assumes the following
53: * variables are defined via the HTTP POST request:
54: *
55: * RDF - the RDF (assumed to be in RDF/XML syntax) to be validated
56: *
57: * SAVE_DOT_FILE - if "on", the GraphViz DOT file is saved and a
58: * link to the file is returned; otherwise the DOT file is not saved
59: *
60: * SAVE_RDF - if "on", the RDF will be copied to a file; otherwise
61: * the RDF is not copied to a file
1.1 barstow 62: *
1.10 barstow 63: * EMBEDDED_RDF - if "on", then the RDF is not enclosed in <RDF>...</RDF>
1.16 barstow 64: * tags; otherwise it assumed that the is enclosed in these tags.
1.10 barstow 65: *
1.16 barstow 66: * URI - the URI of the RDF to validate; this parameter may not be
67: * specified; if this parameter and the RDF parameter are both
68: * specified, this parameter takes precedence
1.1 barstow 69: *
70: * ORIENTATION - the graph's orientation (left to right or top to
1.16 barstow 71: * bottom); default is left to right
1.1 barstow 72: *
1.16 barstow 73: * FONT_SIZE - the font size to use (10, 12, 14, 16 and 20 are
74: * supported); the default is 10
1.1 barstow 75: *
1.16 barstow 76: * ANON_NODES_EMPTY - if "on", anonymous nodes are not labeled; otherwise
77: * anonymous nodes are labeled;
1.12 barstow 78: *
79: * TRIPLES_AND_GRAPH - support values are:
80: *
1.16 barstow 81: * PRINT_BOTH - display triples and a graph (the default)
82: * PRINT_TRIPLES - only display the triples
83: * PRINT_GRAPH - only display the graph
1.12 barstow 84: *
1.1 barstow 85: * GRAPH_FORMAT - the graph's output format. Supported values are:
86: *
1.16 barstow 87: * GIF_EMBED - embed the graph as a GIF (the default)
1.1 barstow 88: * GIF_LINK - don't embed the GIF but create a link for it
89: * SVG_LINK - create the graph in SVG format and create a link to the file
90: * PNG_EMBED - create the graph in PNG format and embed the graph in the
91: * document that is returned
92: * PNG_LINK - create the graph in PNG format and create a link to the file
93: * PS_LINK - create a PostScript image of the file and a link to the file
94: * HP_PCL_LINK - create a HPGL/2 - PCL (Laserwriter) image of the file
95: * and a link to the file
96: * HP_GL_LINK - create a HPGL - PCL (pen plotter) image of the file and
97: * a link to the file
98: *
99: * NTRIPLES if "on" the tabular output will be in the NTriples format;
100: * otherwise a table of Subject, Predicate, Objects will be generated
101: *
1.16 barstow 102: ***********************************************************************
103: *
104: * Server Initialization - this servlet requires the following
105: * parameters be set in the servlet's init() method - via the
106: * ServletConfig object:
1.1 barstow 107: *
1.16 barstow 108: * GRAPH_VIZ_ROOT - the absolute path of the top-level directory containing
109: * GraphViz's binary distribution
110: *
111: * GRAPH_VIZ_PATH - the relative path (based on GRAPH_VIZ_ROOT) of
112: * the DOT executable (e.g. dotneato/dot) - the program used to generate
113: * a graph from a DOT file.
114: *
115: * GRAPH_VIZ_FONT_DIR - the relative path (based on GRAPH_VIZ_ROOT) of
116: * the fonts directory used by GraphViz (e.g. Fonts)
117: *
118: * SERVLET_TMP_DIR - the absolute path of the directory to be used to
119: * store temporary files used by the servlet and GraphViz. This
120: * directory must be writable by the servlet.
121: *
122: * NOTE - Some files created by the servlet are not removed by
123: * servlet (e.g. graph image files).
124: *
125: * If any of these parameters are not defined, the servlet will NOT
126: * validate the RDF.
127: *
128: ***********************************************************************
129: *
130: * Dependencies - this servlet requires the following Java packages
131: * as well as GraphViz (described above):
132: *
133: * ARP RDF parser: http://www.hpl.hp.co.uk/people/jjc/arp/download.html
134: *
135: * SAX-based XML parser: e.g. Xerces at http://xml.apache.org/
136: *
137: * Java servlet package: http://java.sun.com/products/servlet/archive.html
138: *
139: * Apache Regular Expression: http://jakarta.apache.org/builds/jakarta-regexp/release/v1.2/
140: *
141: ***********************************************************************
142: *
143: * Author: Art Barstow <barstow@w3.org>
144: *
1.19 ! duerst 145: * $Id: ARPServlet.java,v 1.18 2002/07/17 08:11:28 duerst Exp $
1.16 barstow 146: *
147: ***********************************************************************/
1.1 barstow 148:
1.16 barstow 149: // http://dev.w3.org/cvsweb/java/classes/org/w3c/rdf/examples/
150: package org.w3c.rdf.examples;
1.1 barstow 151:
152: import java.io.*;
153: import java.net.MalformedURLException;
154: import java.net.URL;
155: import java.util.StringTokenizer;
156: import java.util.Enumeration;
1.14 barstow 157: import java.util.Hashtable;
1.16 barstow 158:
159: // http://java.sun.com/products/servlet/2.2/javadoc/javax/servlet/package-summary.html
160: import javax.servlet.*;
1.1 barstow 161: import javax.servlet.http.*;
162:
1.16 barstow 163: // http://xml.apache.org/apiDocs/org/xml/sax/package-summary.html
164: import org.xml.sax.InputSource;
1.1 barstow 165: import org.xml.sax.Parser;
166: import org.xml.sax.SAXException;
167: import org.xml.sax.SAXParseException;
168: import org.xml.sax.ErrorHandler;
169: import org.xml.sax.helpers.*;
170:
1.16 barstow 171: // http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html
1.3 barstow 172: import org.apache.regexp.RE;
173:
1.16 barstow 174: // http://www.hpl.hp.co.uk/people/jjc/arp/apidocs/index.html
175: import com.hp.hpl.jena.rdf.arp.*;
1.1 barstow 176:
177: public class ARPServlet extends HttpServlet
178: {
1.19 ! duerst 179: final static public String REVISION = "$Id: ARPServlet.java,v 1.18 2002/07/17 08:11:28 duerst Exp $";
1.1 barstow 180:
181: // The email address for bug reports
1.6 barstow 182: private static final String MAIL_TO = "www-rdf-validator@w3.org";
1.1 barstow 183:
184: // Names of the POST parameters (described above) and their
1.12 barstow 185: // defaults (if applicable)
186: private static final String TEXT = "RDF";
187: private static final String SAVE_DOT_FILE = "SAVE_DOT_FILE";
188: private static final String SAVE_RDF = "SAVE_RDF";
189: private static final String EMBEDDED_RDF = "EMBEDDED_RDF";
190: private static final String URI = "URI";
191: private static final String NTRIPLES = "NTRIPLES";
192: private static final String ANON_NODES_EMPTY = "ANON_NODES_EMPTY";
1.1 barstow 193:
194: private static final String NODE_COLOR = "NODE_COLOR";
195: private static final String DEFAULT_NODE_COLOR = "black";
196:
197: private static final String NODE_TEXT_COLOR = "NODE_TEXT_COLOR";
198: private static final String DEFAULT_NODE_TEXT_COLOR = "black";
199:
200: private static final String EDGE_COLOR = "EDGE_COLOR";
201: private static final String DEFAULT_EDGE_COLOR = "black";
202:
203: private static final String EDGE_TEXT_COLOR = "EDGE_TEXT_COLOR";
204: private static final String DEFAULT_EDGE_TEXT_COLOR = "black";
205:
206: private static final String ORIENTATION = "ORIENTATION";
207: private static final String DEFAULT_ORIENTATION = "TB"; // Top to Bottom
208:
209: private static final String FONT_SIZE = "FONT_SIZE";
210: private static final String DEFAULT_FONT_SIZE = "10";
211:
1.12 barstow 212: // Print graph and/or triples
213: private static final String TRIPLES_AND_GRAPH = "TRIPLES_AND_GRAPH";
214: private static final String PRINT_BOTH = "PRINT_BOTH";
215: private static final String PRINT_TRIPLES = "PRINT_TRIPLES";
216: private static final String PRINT_GRAPH = "PRINT_GRAPH";
217:
218: // Graph formats
1.1 barstow 219: private static final String FORMAT = "FORMAT";
220: private static final String FORMAT_GIF_EMBED = "GIF_EMBED";
221: private static final String FORMAT_GIF_LINK = "GIF_LINK";
222: private static final String FORMAT_SVG_LINK = "SVG_LINK";
223: private static final String FORMAT_PNG_EMBED = "PNG_EMBED";
224: private static final String FORMAT_PNG_LINK = "PNG_LINK";
225: private static final String FORMAT_PS_LINK = "PS_LINK";
226: private static final String FORMAT_HP_PCL_LINK = "HP_PCL_LINK";
227: private static final String FORMAT_HP_GL_LINK = "HP_GL_LINK";
228:
229: // Fonts are not currently configurable
230: private static final String DEFAULT_FONT = "arial";
231:
232: // Names of the servlet's parameters - for Jigsaw web server
233: private static final String SERVLET_TMP_DIR = "SERVLET_TMP_DIR";
234: private static final String GRAPH_VIZ_ROOT = "GRAPH_VIZ_ROOT";
235: private static final String GRAPH_VIZ_PATH = "GRAPH_VIZ_PATH";
236: private static final String GRAPH_VIZ_FONT_DIR = "GRAPH_VIZ_FONT_DIR";
237:
238: // Variables for the servlet's parameters
239: private static String m_ServletTmpDir = null;
240: private static String m_GraphVizPath = null;
241: private static String m_GraphVizFontDir = null;
242:
243: // Names of environment variable need by GraphVis
244: private static String DOTFONTPATH = "DOTFONTPATH";
245: private static String LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
246:
247: // Names used for temporary files
248: private static final String TMP_FILE_PREFIX = "servlet_";
249: private static final String SUFFIX_TMP_DIR = ".tmp";
250: private static final String SUFFIX_DOT = ".dot";
251: private static final String SUFFIX_RDF = ".rdf";
252:
253: // Names used for file suffixes and for GraphViz's command line
254: // option
255: private static final String NAME_GIF = "gif";
256: private static final String NAME_HPGL = "hpgl";
257: private static final String NAME_PCL = "pcl";
258: private static final String NAME_PNG = "png";
259: private static final String NAME_PS = "ps";
260: private static final String NAME_SVG = "svg";
261:
262: // Default GraphViz parameter names and their default values
263: // Servlet name
264: private static final String SERVLET_NAME = "ARPServlet";
265:
266: // Name for the DOT file title
267: private static final String DOT_TITLE = "dotfile";
268:
1.14 barstow 269: // The string to use for to prefix anonymous nodes.
270: private static final String ANON_NODE = "genid:";
271:
1.1 barstow 272: // The string to use for a namespace name when no
273: // namespace is available - e.g. for the RDF that is
274: // directly entered into the input form.
1.14 barstow 275: private static final String DEFAULT_NAMESPACE = "online:";
1.1 barstow 276:
277: /*
1.14 barstow 278: * Create a File object from the given directory and file names
1.1 barstow 279: *
280: *@param directory the file's directory
281: *@param prefix the file's prefix name (not its directory)
282: *@param suffix the file's suffix or extension name
283: *@return a File object if a temporary file is created; null otherwise
284: */
1.4 barstow 285: private File createTempFile (String directory, String prefix, String suffix)
286: {
1.1 barstow 287: File f;
288: try {
289: File d = new File(directory);
290: f = File.createTempFile(prefix, suffix, d);
291: } catch (Exception e) {
292: return null;
293: }
294: return f;
295: }
296:
297: /*
298: * Given a URI string, open it, read its contents into a String
299: * and return the String
300: *
301: *@param uri the URI to open
302: *@return the content at the URI or null if any error occurs
303: */
1.4 barstow 304: private String getByteStream (String uri)
305: {
1.1 barstow 306: try {
307: URL url = new URL(uri);
308: InputStream is = url.openStream();
309: String s = new String("");
310:
311: int c;
312: int numRead = 0;
313:
314: while ((c = is.read()) != -1) {
315: s += (char)c;
316: if (numRead == 15) {
317: // A server could return content but not the RDF/XML that
318: // we need. Check the beginning of s and if it looks like
319: // a generic HTML message, return an error.
320: if (s.startsWith("<!DOCTYPE"))
321: return null;
322: }
323: numRead++;
324: }
325:
326: if (s.equals(""))
327: // Nothing was returned
328: return null;
329:
330: return s;
331:
332: } catch (Exception e) {
333: return null;
334: }
335: }
336:
337: /*
1.4 barstow 338: * Copy the given string of RDF to a file in the given directory.
339: * This is only done if the servlet is explictly asked to save
340: * the RDF to a file.
1.1 barstow 341: *
1.14 barstow 342: *@param tmpDir the file's directory
1.1 barstow 343: *@param rdf the string of RDF
344: */
345: private void copyRDFStringToFile(String tmpDir, String rdf)
346: {
347: try {
348: // Generate a unique file name
349: File tmpFile = createTempFile(tmpDir, TMP_FILE_PREFIX, SUFFIX_RDF);
350: if (tmpFile == null) {
351: // Not really a critical error, just return
352: return;
353: }
354:
355: // Create a PrintWriter for the GraphViz consumer
356: FileWriter fw = new FileWriter(tmpFile);
357: PrintWriter pw = new PrintWriter(fw);
358:
359: pw.println(rdf);
360: pw.close();
361: } catch (Exception e) {
1.4 barstow 362: System.err.println(SERVLET_NAME + ": error occured trying to save RDF to file '" + tmpDir + TMP_FILE_PREFIX + SUFFIX_RDF + "'.");
1.1 barstow 363: return;
364: }
365: }
366:
367: /*
368: * Given the graph's format option, return either the corresponding
369: * command line option for that option or the file name suffix for
370: * the graph option. For example GIF files have ".gif" for its
371: * suffix and GraphViz uses "-Tgif" for the command line.
372: *
373: * NOTE: default is GIF.
374: *
375: *@param graphFormat the graph's output format
376: *@param suffix. If true, the name returned is for the graph's
377: * file name suffix; otherwise, the name returned is for the
378: * graph's command line option.
379: *@return the suffix to use for the graph's output file
380: */
381: private String getFormatName(String graphFormat, boolean suffix) {
382:
383: String name = (suffix) ? "." : "-T";
384:
1.4 barstow 385: if (graphFormat.equals(FORMAT_PNG_EMBED)) return name + NAME_PNG;
386: if (graphFormat.equals(FORMAT_PNG_LINK)) return name + NAME_PNG;
387: if (graphFormat.equals(FORMAT_SVG_LINK)) return name + NAME_SVG;
388: if (graphFormat.equals(FORMAT_PS_LINK)) return name + NAME_PS;
389: if (graphFormat.equals(FORMAT_HP_GL_LINK)) return name + NAME_HPGL;
1.1 barstow 390: if (graphFormat.equals(FORMAT_HP_PCL_LINK)) return name + NAME_PCL;
391:
392: return name + NAME_GIF;
393: }
394:
395: /*
396: * Invokes the GraphVis program to create a graph image from the
397: * the given DOT data file
398: *
399: *@param dotFileName the name of the DOT data file
400: *@param outputFileName the name of the output data file
1.14 barstow 401: *@param graphFormat the graph's format
1.1 barstow 402: *@return true if success; false if any failure occurs
403: */
1.8 barstow 404: private boolean generateGraphFile(String dotFileName,
1.4 barstow 405: String outputFileName, String graphFormat)
406: {
1.16 barstow 407: String environment[] = {DOTFONTPATH + "=" + m_GraphVizFontDir};
1.1 barstow 408:
409: String formatOption = getFormatName(graphFormat, false);
410:
411: String cmdArray[] = {m_GraphVizPath, formatOption, "-o", outputFileName, dotFileName};
412: Runtime rt = Runtime.getRuntime();
413: try {
414: Process p = rt.exec(cmdArray, environment);
415: p.waitFor();
1.10 barstow 416:
1.1 barstow 417: } catch (Exception e) {
418: System.err.println("Error: generating OutputFile.");
419: return false;
420: }
421: return true;
422: }
423:
424: /*
425: * Returns a parameter from a request or the parameter's default
426: * value.
427: *
428: *@param req a Servlet request
1.14 barstow 429: *@param param the name of the parameter
430: *@param defString the string returned if the param is not found
1.1 barstow 431: *@return if the request contains the specfied parameter its value
432: * in the request is returned; otherwise its default value is
433: * returned
434: */
435: private String getParameter(HttpServletRequest req, String param,
436: String defString)
437: {
438: String s = req.getParameter(param);
439: return (s == null) ? defString : s;
440: }
441:
442: /*
443: * If the request contains any graph-related parameters, pass them
444: * to the graph consumer for handling
445: *
446: *@param req the response
1.14 barstow 447: *@param pw the PrintWriter
1.1 barstow 448: *@param consumer the GraphViz consumer
449: */
1.14 barstow 450: private void processGraphParameters (HttpServletRequest req, PrintWriter pw)
1.1 barstow 451: {
1.4 barstow 452: // Print the graph header
453: pw.println("digraph " + DOT_TITLE + "{ " );
1.1 barstow 454:
455: // Look for colors
1.4 barstow 456: String nodeColor = getParameter(req, NODE_COLOR,
457: DEFAULT_NODE_COLOR);
458: String nodeTextColor = getParameter(req, NODE_TEXT_COLOR,
459: DEFAULT_NODE_TEXT_COLOR);
460: String edgeColor = getParameter(req, EDGE_COLOR,
461: DEFAULT_EDGE_COLOR);
462: String edgeTextColor = getParameter(req, EDGE_TEXT_COLOR,
463: DEFAULT_EDGE_TEXT_COLOR);
464: String fontSize = getParameter(req, FONT_SIZE,
465: DEFAULT_FONT_SIZE);
1.1 barstow 466:
467: // Orientation must be either
468: String orientation = req.getParameter (ORIENTATION);
469: if (orientation.equals("LR"))
470: orientation = "LR";
471: else
472: orientation = DEFAULT_ORIENTATION;
473:
474: // Add an attribute for all of the graph's nodes
475: pw.println("node [fontname=" + DEFAULT_FONT +
1.7 barstow 476: ",fontsize=" + fontSize +
477: ",color=" + nodeColor +
1.12 barstow 478: ",fontcolor=" + nodeTextColor + "];");
1.1 barstow 479:
480: // Add an attribute for all of the graph's edges
481: pw.println("edge [fontname=" + DEFAULT_FONT +
1.8 barstow 482: ",fontsize=" + fontSize +
483: ",color=" + edgeColor +
484: ",fontcolor=" + edgeTextColor + "];");
1.1 barstow 485:
486: // Add an attribute for the orientation
487: pw.println("rankdir=" + orientation + ";");
488: }
489:
490: private static class SaxErrorHandler implements org.xml.sax.ErrorHandler
491: {
492: ServletOutputStream out;
493: boolean silent = false;
1.5 barstow 494: String fatalErrors = "";
495: String errors = "";
496: String warnings = "";
1.1 barstow 497:
498: /*
499: * Constructuor for a SaxErrorHandler
500: *
501: *@param out the servlet's output stream
502: *@param silent if false, output is suprressed
503: */
504: public SaxErrorHandler(ServletOutputStream out, boolean silent)
505: {
506: this.out = out;
507: this.silent = silent;
508: }
509:
510: /*
511: * Create a formatted string from the exception's message
512: *
1.5 barstow 513: *@param e the SAX Parse Exception
1.1 barstow 514: *@return a formatted string
515: */
516: private static String format(org.xml.sax.SAXParseException e)
517: {
518: String msg = e.getMessage();
519: if (msg == null)
520: msg = e.toString();
521: return msg + "[Line = " + e.getLineNumber() + ", Column = " + e.getColumnNumber() + "]";
522: }
523:
524: /*
525: * Handle a parse error
526: *
1.5 barstow 527: *@param e the SAX Parse Exception
1.1 barstow 528: */
529: public void error(org.xml.sax.SAXParseException e)
530: throws org.xml.sax.SAXException
531: {
532: if (this.silent) return;
533:
1.5 barstow 534: this.errors += "Error: " + format(e) + "<br />";
1.1 barstow 535: }
536:
537: /*
538: * Handle a fatal parse error
539: *
1.5 barstow 540: *@param e the SAX Parse Exception
1.1 barstow 541: */
542: public void fatalError(org.xml.sax.SAXParseException e)
543: throws org.xml.sax.SAXException
544: {
545: if (this.silent) return;
546:
1.5 barstow 547: this.fatalErrors += "FatalError: " + format(e) + "<br />";
1.1 barstow 548: }
549:
550: /*
551: * Handle a parse warning
552: *
1.5 barstow 553: *@param e the SAX Parse Exception
1.1 barstow 554: */
555: public void warning(org.xml.sax.SAXParseException e)
556: throws org.xml.sax.SAXException
557: {
558: if (this.silent) return;
559:
1.5 barstow 560: this.warnings += "Warning: " + format(e) + "<br />";
1.1 barstow 561: }
1.5 barstow 562:
563: /*
564: * Return the error messages
565: *
566: *@return the error messages or an empty string if there are
567: * no messages
568: */
569: public String getErrors()
570: {
571: return this.errors;
572: }
573:
574: /*
575: * Return the fatal error messages
576: *
577: *@return the fatal error messages or an empty string if there are
578: * no messages
579: */
580: public String getFatalErrors()
581: {
582: return this.fatalErrors;
583: }
584:
585: /*
586: * Return the warning messages
587: *
588: *@return the warning messages or an empty string if there are
589: * no messages
590: */
591: public String getWarnings()
592: {
593: return this.warnings;
594: }
1.1 barstow 595: }
596:
597: /*
598: * Generate a graph of the RDF data model
599: *
600: *@param out the servlet's output stream
1.4 barstow 601: *@param pw the graph file's PrintWriter
602: *@param dotFile the File handle for the graph file
1.1 barstow 603: *@param rdf the RDF text
604: *@param req a Servlet request
605: *@param graphFormat the graph's format
606: *@param saveRDF the RDF can be cached [saved to the file system]
607: *@param saveDOTFile the DOT file should be cached
608: */
1.8 barstow 609: private void generateGraph(ServletOutputStream out, PrintWriter pw,
1.4 barstow 610: File dotFile, String rdf, HttpServletRequest req, String graphFormat,
1.1 barstow 611: boolean saveRDF, boolean saveDOTFile)
612: {
613: try {
614: out.println("<hr title=\"visualisation\">");
615: out.println("<h3>Graph of the data model</h3>");
616:
617: // The temporary directory
618: String tmpDir = m_ServletTmpDir;
619:
620: // Add the graph footer
621: pw.println( " }");
622:
1.4 barstow 623: // Close the DOT input file so the GraphViz can
1.1 barstow 624: // open and read it
625: pw.close();
626:
627: // Generate a unique file name for the output file
628: // that will be created
629: String suffix = getFormatName(graphFormat, true);
630: File outputFile = createTempFile(tmpDir, TMP_FILE_PREFIX, suffix);
631: if (outputFile == null) {
632: out.println("Failed to create a temporary file for the graph. A graph cannot be generated.");
633: dotFile.delete();
634: return;
635: }
636:
637: // Pass the DOT data file to the GraphViz dot program
638: // so it can create a graph image of the data model
639: String dotFileName = dotFile.getAbsolutePath();
640: String outputFileName = outputFile.getAbsolutePath();
641:
1.8 barstow 642: if (!generateGraphFile(dotFileName, outputFileName, graphFormat)) {
1.1 barstow 643: out.println("An attempt to create a graph failed.");
644: dotFile.delete();
645: outputFile.delete();
646: return;
647: }
648: // Handle the DOT file
649: if (saveDOTFile) {
650: // Make the DOT file link'able if so requested
651: String dotPath = SERVLET_NAME + SUFFIX_TMP_DIR +
652: File.separator + dotFile.getName();
653: out.println("<a href=\"" + dotPath + "\">Download the DOT file.</a><br /><br />");
654: }
655: else {
656: // Delete it ...
657: dotFile.delete();
658: }
659:
660: // NOTE: Cannot delete the output file here because its
661: // pathname is returned to the client
662: String imagePath = SERVLET_NAME + SUFFIX_TMP_DIR + File.separator +
663: outputFile.getName();
664:
665: // Handle the embedded image formats first
666: if (graphFormat.equals(FORMAT_GIF_EMBED) ||
667: graphFormat.equals(FORMAT_PNG_EMBED)) {
668: if (outputFile.length() > 0)
669: out.println("<img src=\"" + imagePath + "\"/>");
670: else
671: out.println("The graph image file is empty.");
672: } else {
673: if (outputFile.length() > 0)
674: out.println("<a href=\"" + imagePath + "\">Get/view the graph's image file (" + suffix + ").</a><br /><br />");
675: else
676: out.println("The graph image file is empty.");
677: }
678:
679: // One last thing to do before exiting - copy the RDF to a file
680: if (saveRDF)
681: copyRDFStringToFile(tmpDir, rdf);
682:
683: } catch (Exception e) {
684: System.err.println("Exception generating graph: " + e.getMessage());
685: }
686: }
687:
688: /*
689: * Search the given string for substring "key"
690: * and if it is found, replace it with string "replacement"
691: *
692: *@param input the input string
693: *@param key the string to search for
694: *@param replacement the string to replace all occurences of "key"
1.3 barstow 695: *@return if no substitutions are done, input is returned; otherwise
1.1 barstow 696: * a new string is returned.
697: */
698: public static String replaceString(String input, String key,
699: String replacement)
700: {
1.3 barstow 701: try {
702: RE re = new RE(key);
703: return re.subst(input, replacement);
704: } catch (Exception e) {
705: return input;
1.1 barstow 706: }
707: }
708:
709: /*
710: * Print the document's header info
711: *
712: *@param out the servlet's output stream
713: */
714: private void printDocumentHeader (ServletOutputStream out)
715: {
716: try {
717:
1.6 barstow 718: out.println( "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"" +
719: " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" +
720: "<html><head>" +
721: "<title>RDF Validator</title>" +
722: "<link href='http://www.w3.org/StyleSheets/base.css' rel='stylesheet' type='text/css'/>" +
723: "<style type='text/css'>" +
724: " TD {" +
725: " background:#EEEEEE;" +
726: " font-family:'courier new',courier,serif;" +
727: " }" +
728: "</style>" +
729: "</head>" +
730: "<body>");
1.1 barstow 731:
732: } catch (Exception e) {
1.8 barstow 733: System.err.println("Exception (printDocumentHeader): " + e.getMessage());
1.1 barstow 734: }
735: }
736:
737: /*
738: * Print the rdf listing
739: *
740: *@param out the servlet's output stream
741: *@param rdf the RDF code
1.14 barstow 742: *@param needCR if true, add a CarriageReturn to the output; if false,
743: * do not add it
1.1 barstow 744: */
745: private void printListing (ServletOutputStream out, String rdf,
746: boolean needCR)
747: {
748: try {
1.8 barstow 749: out.println("<hr title=\"original source\">" +
750: "<h3>The original RDF/XML document</h3>" +
751: "<pre>");
1.1 barstow 752:
753: String s = replaceString(rdf, "<", "<");
754:
755: // Now output the RDF one line at a time with line numbers
756: int lineNum = 1;
757: int nl = 0;
758: String terminator = needCR?"\n":"";
759: do {
760: String tok;
761: nl = s.indexOf('\n');
762: if ( nl == -1 ) {
763: tok = s;
764: } else {
765: tok = s.substring(0,nl);
766: s = s.substring(nl+1);
767: }
1.8 barstow 768: out.print("<a name=\"" + lineNum + "\">" + lineNum +
769: "</a>: " + tok + terminator);
1.1 barstow 770: lineNum++;
771: } while ( nl != -1 );
772:
773: out.println("</pre>");
774: } catch (Exception e) {
1.8 barstow 775: System.err.println("Exception (printListing): " + e.getMessage());
1.1 barstow 776: }
777: }
778:
779: /*
780: * Print the header for the triple listing
781: *
782: *@param out the servlet's output stream
1.14 barstow 783: *@param nTriples if true, output is N-Triples syntax
1.1 barstow 784: */
785: private void printTripleTableHeader (ServletOutputStream out, boolean nTriples)
786: {
787: try {
788: if (nTriples) {
1.6 barstow 789: out.println("<h3>Triples of the Data Model in " +
790: "<a href=\"http://www.w3.org/2001/sw/RDFCore/ntriples/\">" +
791: "N-Triples</a> Format (Sub, Pred, Obj)</h3>" +
792: "<pre>");
1.1 barstow 793: } else {
794: out.println("<hr title=\"triples\">");
795: out.println("<h3>Triples of the Data Model</h3>");
796: out.println("<table border><tr>" +
797: "<td><b>Number</b></td>" +
798: "<td><b>Subject</b></td>" +
799: "<td><b>Predicate</b></td>" +
800: "<td><b>Object</b></td>" +
801: "</tr>");
802: }
803: } catch (Exception e) {
1.8 barstow 804: System.err.println("Exception (printTripleTableHeader): " + e.getMessage());
1.1 barstow 805: }
806: }
807:
808: /*
809: * Print the footer info for the triple listing
810: *
811: *@param out the servlet's output stream
1.14 barstow 812: *@param nTriples if true, output is N-Triples syntax
1.1 barstow 813: */
814: private void printTripleTableFooter (ServletOutputStream out,
815: boolean nTriples)
816: {
817: try {
818: if (nTriples)
819: out.println("</pre>");
820: else
821: out.println("</table>");
822: } catch (Exception e) {
1.8 barstow 823: System.err.println("Exception (printTripleTableFooter): " + e.getMessage());
1.1 barstow 824: }
825: }
826:
827: /*
828: * Print the document's footer info
829: *
830: *@param out the servlet's output stream
831: *@param rdf the RDF code
832: */
833: private void printDocumentFooter (ServletOutputStream out, String rdf)
834: {
835: try {
836:
1.8 barstow 837: String s;
838:
839: s = "<hr title=\"Problem reporting\">" +
840: "<h3>Feedback</h3>" +
841: "<p>If you suspect the parser is in error, please enter an explanation below and then press the <b>Submit problem report</b> button, to mail the report (and listing) to <i>" + MAIL_TO + "</i></p>" +
842: "<form enctype='text/plain' method='post' action='mailto:" + MAIL_TO + "'>" +
1.9 barstow 843: "<textarea cols='60' rows='4' name='report'></textarea>";
1.8 barstow 844: out.println(s);
1.1 barstow 845:
1.9 barstow 846: out.println("<input type='hidden' name='RDF' value=\"<?xml version="1.0">");
847:
1.1 barstow 848: // The listing is being passed as a parameter so the '<'
849: // and '"' characters must be replaced with < and ",
850: // respectively
851: if (rdf != null) {
1.9 barstow 852: String s1;
853: s1 = replaceString(rdf, "<", "<");
1.11 barstow 854: s1 = replaceString(s1, ">", ">");
1.9 barstow 855: s1 = replaceString(s1, "\"", """);
856: out.println(s1);
1.1 barstow 857: }
1.9 barstow 858: out.println("\"\\>");
1.1 barstow 859:
1.8 barstow 860: out.println("<input type='submit' value='Submit problem report'\\>" +
1.9 barstow 861: "</form></body></html>");
1.1 barstow 862:
863: } catch (Exception e) {
1.8 barstow 864: System.err.println("Exception (printDocumentFooter): " + e.getMessage());
1.1 barstow 865: }
866: }
867:
868: /*
869: * Servlet's get info method
870: */
871: public String getServletInfo () {
872: return "Servlet wrapper for the ARP RDF parser. This is revision " + REVISION;
873: }
874:
875: /*
876: * Servlet's init method
877: *
878: *@param config the servlet's configuration object
879: *@throws ServletException
880: */
881: public void init(ServletConfig config) throws ServletException
882: {
883: super.init (config);
884:
885: // Cache the parameters
886: m_ServletTmpDir = config.getInitParameter(SERVLET_TMP_DIR);
887:
888: // All of the Graph Viz paths extend from GRAPH_VIZ_ROOT
889: String GraphVizRoot = config.getInitParameter(GRAPH_VIZ_ROOT);
890:
891: m_GraphVizPath = GraphVizRoot + "/" + config.getInitParameter(GRAPH_VIZ_PATH);
892: m_GraphVizFontDir = GraphVizRoot + "/" + config.getInitParameter(GRAPH_VIZ_FONT_DIR);
893:
894: if (m_ServletTmpDir == null || GraphVizRoot == null) {
895: System.err.println (
896: "<html>" +
897: "<h1>Servlet Initialization Error</h1>" +
898: "<h2>One or more of the following parameters has not been initialized: " +
899: SERVLET_TMP_DIR + "," + GRAPH_VIZ_ROOT + "," +
1.16 barstow 900: GRAPH_VIZ_FONT_DIR + "," + GRAPH_VIZ_PATH + "." +
1.1 barstow 901: "</h2>" +
902: "</html>");
903: }
904: }
905:
906: /*
907: * Servlet's destroy info method
908: */
909: public void destroy () {
910: super.destroy ();
911: }
912:
913: /*
914: * Servlet's doGet info method - NOT supported
915: *
916: *@param req the request
917: *@param res the response
918: *@throws ServletException, IOException
919: */
920: public void doGet (HttpServletRequest req, HttpServletResponse res)
921: throws ServletException, IOException
922: {
923: String sRDF = req.getParameter(TEXT);
924: String sURI = req.getParameter(URI);
925:
926: if (sURI == null && sRDF == null) {
927: ServletOutputStream out = res.getOutputStream ();
928:
1.6 barstow 929: out.println("<h1>Data Error</h1>" +
930: "Must specify the RDF (RDF is a string) or the URI parameter." +
931: "</h1>");
1.1 barstow 932: return;
933: }
934:
935: process(req, res,
936: (sRDF != null) ? java.net.URLDecoder.decode(sRDF) : null,
937: (sURI != null) ? java.net.URLDecoder.decode(sURI) : null);
938: }
939:
940: /*
1.19 ! duerst 941: * Convenience method to convert some String wrongly read in with iso-8859-1 to utf-8
! 942: *
! 943: *@param str the String (input and output)
! 944: */
! 945: private String ISO88591toUTF8 (String str)
! 946: {
! 947: return String(str.getBytes("iso-8859-1"), "utf-8");
! 948: }
! 949:
! 950: /*
1.1 barstow 951: * Servlet's doPost method
952: *
953: *@param req the request
954: *@param res the response
1.17 duerst 955: *@throws ServletException, IOException, java.io.UnsupportedEncodingException
1.1 barstow 956: */
957: public void doPost (HttpServletRequest req, HttpServletResponse res)
958: throws ServletException, IOException
959: {
1.19 ! duerst 960: // String encoding = req.getCharacterEncoding();
! 961: // if (encoding == null) {
! 962: // req.setCharacterEncoding("UTF-8");
! 963: // }
! 964: String sRDF = ISO88591toUTF8 (req.getParameter (TEXT));
! 965: String sURI = ISO88591toUTF8 (req.getParameter (URI));
1.1 barstow 966:
967: if (sURI == null && sRDF == null) {
968: ServletOutputStream out = res.getOutputStream ();
969:
970: out.println("<h1>Neither the RDF or an URI was specified" +
971: "and one of them must be specified.</h1>");
972: return;
973: }
974:
975: process(req,res,sRDF, sURI);
976: }
977:
978: /*
979: * Output a Resource in NTriples syntax
980: *
981: *@param out the servlet's output stream
982: *@param r the Resource to output
983: */
984: static private void printResource(ServletOutputStream out, AResource r)
985: {
986: try {
987: if (r.isAnonymous() )
988: out.print("_:j" + r.getAnonymousID() + " ");
989: else
990: out.print("<" + r.getURI() + "> ");
991: } catch (IOException ioe) {
992: System.err.println("IOException: printing resource.");
993: }
994: }
995:
996: /*
1.18 duerst 997: * Convert to Hex and padd left with zeroes
998: *
999: *@param in the integer to convert and padd
1000: *@param in the length of the result
1001: *@return the padded string
1002: */
1003: // MJD: is there an easier way to do this?
1004: static private String hexPadd (Integer number, Integer length)
1005: {
1006: String t = Integer.toHexString(number).toUpperCase();
1007: Integer hexlength = t.length();
1008:
1009: if ( hexlength > length ) { // too long, truncate
1010: hexlength = length;
1011: }
1012:
1013: Integer zerolength = length - hexlength;
1014: String r = "";
1015:
1016: for (int i=0; i < zerolength; i++) {
1017: r += "0";
1018: }
1019: for (int i=0; i < hexlength; i++) {
1020: r += t.CharAt(i);
1021: }
1022: return r;
1023: }
1024:
1025: /*
1.1 barstow 1026: * Output a Literal in NTriples syntax
1027: *
1028: *@param out the servlet's output stream
1029: *@param l the Literal to output
1030: */
1.3 barstow 1031: static private void printNTripleLiteral(ServletOutputStream out, ALiteral l)
1.1 barstow 1032: {
1033: try {
1034: out.print("\"");
1035: char ar[] = l.toString().toCharArray();
1036:
1037: for (int i=0;i<ar.length;i++) {
1038: switch (ar[i]) {
1039: case '\\':
1040: out.print("\\\\");
1041: break;
1042: case '"':
1043: out.print("\\\"");
1044: break;
1045: case '\n':
1046: out.print("\\n");
1047: break;
1048: case '\r':
1049: out.print("\\r");
1050: break;
1051: case '\t':
1052: out.print("\\t");
1053: break;
1.18 duerst 1054: default:
1055: if ( ar[i] >= 32 && ar[i] <= 127 )
1056: out.print(ar[i]);
1057: else if ( ar[i] < 0xD800 || ar[i] >= 0xE000)
1058: out.print("\\u" + hexPadd(Integer.toHexString(ar[i]).toUpperCase(), 4) );
1059: else // deal with surrogates {
1060: // check for correct surrogate pair
1061: // this code should probably move somewhere else:
1062: // check when we get the input
1063: if ( ar[i] >= 0xDC00 ) {
1064: out.print("{{{error: lone low surrogate}}}");
1065: }
1066: else if ( ++i >= ar.length ) {
1067: out.print("{{{error: lone surrogate at end of string}}}");
1068: }
1069: else if ( ar[i] < 0xDC00 || ar[i] >= 0xE000 ) {
1070: out.print("{{{error: high surrogate not followed by low surrogate}}}");
1071: }
1072: // no errors, actually print
1073: else {
1074: Integer scalarvalue = 0x10000 + (ar[i-1] * 1024) + ar[i];
1075: out.print("\\U" + hexPadd(Integer.toHexString(scalarvalue).toUpperCase(), 8) );
1076: }
1077: }
1.1 barstow 1078: }
1079: }
1080: out.print("\" ");
1081: } catch (IOException ioe) {
1082: System.err.println("IOException: printing literal.");
1083: }
1084: }
1085:
1086: /*
1087: * Control point for outputing an triple in NTriple syntax
1088: *
1089: *@param out the servlet's output stream
1090: *@param subj the subject
1091: *@param pred the predicate
1092: *@param objRes the object as a Resource (may be null)
1093: *@param objLit the object as a Literal (may be null)
1094: */
1095: static private void printNTriple(ServletOutputStream out, AResource subj,
1096: AResource pred, AResource objRes, ALiteral objLit)
1097: {
1098: try {
1099: printResource(out, subj);
1100: printResource(out, pred);
1101: if (objRes != null)
1102: printResource(out, objRes);
1103: else
1.3 barstow 1104: printNTripleLiteral(out, objLit);
1.1 barstow 1105: out.println(".");
1106: } catch (IOException ioe) {
1107: System.err.println("IOException: printing NTriple.");
1108: }
1109: }
1110:
1111: /*
1112: * Create a HTML anchor from the URI or anonNode of the
1113: * given Resource
1114: *
1.14 barstow 1115: *@param r the Resource
1.1 barstow 1116: *@return the string as an HTML anchor
1117: */
1118: static private String addAnchor(AResource r)
1119: {
1120: if (r.isAnonymous())
1.14 barstow 1121: return ANON_NODE + r.getAnonymousID();
1.1 barstow 1122: else
1123: return "<a href='" + r.getURI() + "'>" + r.getURI() + "</a>";
1124: }
1125:
1126: /*
1127: * Output a triple as a row in HTML
1128: *
1129: *@param out the servlet's output stream
1130: *@param subj the subject
1131: *@param pred the predicate
1132: *@param objRes the object as a Resource (may be null)
1133: *@param objLit the object as a Literal (may be null)
1134: *@param num the statement number
1135: */
1136: static private void printTableRow(ServletOutputStream out, AResource subj,
1137: AResource pred, AResource objRes, ALiteral objLit, int num)
1138: {
1139: try {
1140: out.println("<tr><td>" + num + "</td>");
1141: out.println("<td>" + addAnchor(subj) + "</td>");
1142: out.println("<td>" + addAnchor(pred) + "</td>");
1143: if (objRes != null)
1144: out.println("<td>" + addAnchor(objRes) + "</td>");
1145: else {
1146: out.println("<td>");
1.3 barstow 1147: String s1 = objLit.toString().trim();
1148: s1 = replaceString(s1, "<", "<");
1149: s1 = replaceString(s1, ">", ">");
1150: out.println(s1);
1.1 barstow 1151: out.println("</td>");
1152: }
1153: out.println("</tr>");
1154: } catch (IOException ioe) {
1155: System.err.println("IOException: printing TableRow.");
1156: }
1157: }
1158:
1.4 barstow 1159: private static class SH implements StatementHandler
1.1 barstow 1160: {
1161: ServletOutputStream out;
1.12 barstow 1162: PrintWriter pw;
1.1 barstow 1163: boolean isNTriples;
1.12 barstow 1164: boolean printTriples;
1165: boolean printGraph;
1166: boolean anonNodesEmpty;
1.14 barstow 1167: int numStatements;
1168: int numLiterals;
1169: Hashtable subjects;
1170: int numSubjects;
1.1 barstow 1171:
1172: /*
1.4 barstow 1173: * Constructuor for the StatementHandler. The primary
1174: * responsiblitly is to cache init variables
1.1 barstow 1175: *
1176: *@param out the servlet's output stream
1.4 barstow 1177: *@param pw the Dot file's PrintWriter
1.1 barstow 1178: * syntax; otherwise use HTML syntax
1.12 barstow 1179: *@param isNTriples if true, output using the NTriples
1180: *@param printTriples if true, print the triples
1181: *@param printGraph if true, create the graph file
1182: *@param printGraph if true, anonomyous nodes should be empty
1.1 barstow 1183: */
1.12 barstow 1184: public SH(ServletOutputStream out, PrintWriter pw, boolean isNTriples,
1185: boolean printTriples, boolean printGraph, boolean anonNodesEmpty)
1.1 barstow 1186: {
1187: this.out = out;
1.12 barstow 1188: this.pw = pw;
1.1 barstow 1189: this.isNTriples = isNTriples;
1.12 barstow 1190: this.printTriples = printTriples;
1191: this.printGraph = printGraph;
1192: this.anonNodesEmpty = anonNodesEmpty;
1.14 barstow 1193:
1194: this.numStatements = 0;
1195: this.numLiterals = 0;
1196:
1197: this.subjects = new Hashtable();
1198: this.numSubjects = 0;
1.4 barstow 1199: }
1200:
1201: /*
1202: * Generic handler for a Resource/Resource/Resource triple (S/P/O).
1203: * Dispatches to the methods that do the real work.
1204: *
1205: *@param subj the subject
1206: *@param pred the predicate
1207: *@param obj the object (as a Resource)
1208: */
1209: public void statement(AResource subj, AResource pred, AResource obj)
1210: {
1.12 barstow 1211: if (printTriples)
1212: statementResource(subj, pred, obj);
1213: if (printGraph)
1214: statementDotResource(subj, pred, obj);
1.4 barstow 1215: }
1216:
1217: /*
1218: * Generic handler for a Resource/Resource/Resource triple (S/P/O).
1219: * Dispatches to the methods that do the real work.
1220: *
1221: *@param subj the subject
1222: *@param pred the predicate
1223: *@param obj the object (as a Literal)
1224: */
1225: public void statement(AResource subj, AResource pred, ALiteral lit)
1226: {
1.13 barstow 1227: numLiterals++;
1228:
1.12 barstow 1229: if (printTriples)
1230: statementLiteral(subj, pred, lit);
1231: if (printGraph)
1232: statementDotLiteral(subj, pred, lit);
1.1 barstow 1233: }
1234:
1235: /*
1236: * Handler for a Resource/Resource/Resource triple (S/P/O)
1237: * Outputs the given triple using NTriples or HTML syntax.
1238: *
1239: *@param subj the subject
1240: *@param pred the predicate
1241: *@param obj the object (as a Resource)
1242: */
1.4 barstow 1243: public void statementResource(AResource subj, AResource pred, AResource obj)
1.1 barstow 1244: {
1245: numStatements++;
1246:
1247: if (this.isNTriples)
1248: printNTriple(out, subj, pred, obj, null);
1249: else
1250: printTableRow(out, subj, pred, obj, null, this.numStatements);
1251: }
1.4 barstow 1252:
1.1 barstow 1253: /*
1254: * Handler for a Resource/Resource/Literal triple (S/P/O)
1255: * Outputs the given triple using NTriples or HTML syntax.
1256: *
1257: *@param subj the subject
1258: *@param pred the predicate
1259: *@param obj the object (as a Literal)
1260: */
1.4 barstow 1261: public void statementLiteral(AResource subj, AResource pred, ALiteral lit)
1.1 barstow 1262: {
1263: numStatements++;
1264:
1265: if (this.isNTriples)
1266: printNTriple(out, subj, pred, null, lit);
1267: else
1268: printTableRow(out, subj, pred, null, lit, this.numStatements);
1269: }
1.4 barstow 1270:
1.12 barstow 1271: /*
1272: * Print the first part of a triple's Dot file. See below for
1273: * more info. This is the same regardless if the triple's
1274: * object is a Resource or a Literal
1275: *
1276: *@param subj the subject
1277: */
1278: public void printFirstPart(AResource subj)
1279: {
1.14 barstow 1280: if (subj.isAnonymous()) {
1.12 barstow 1281: if (this.anonNodesEmpty) {
1.14 barstow 1282: Integer n = (Integer) subjects.get(subj.getAnonymousID());
1283: if (n == null) {
1284: this.numSubjects++;
1285: subjects.put(subj.getAnonymousID(), new Integer(this.numSubjects));
1286: this.pw.println("\"" + ANON_NODE +
1287: subj.getAnonymousID() + "\" [label=\" \"];");
1288: }
1.12 barstow 1289: }
1.14 barstow 1290: this.pw.print("\"" + ANON_NODE + subj.getAnonymousID());
1.12 barstow 1291: } else {
1292: this.pw.println("\"" + subj.getURI() + "\" [URL=\"" +
1293: subj.getURI() + "\"];");
1294: this.pw.print("\"" + subj.getURI());
1295: }
1296: }
1297:
1.4 barstow 1298: /*
1299: * Handler for a Resource/Resource/Resource triple (S/P/O).
1300: * Outputs the given triple using Dot syntax.
1.12 barstow 1301: *
1302: * Each triple will be output in three lines of DOT code as
1303: * follows (not including the complication of anon nodes
1304: * and the possiblity that the anon nodes may be named
1305: * with an empty string):
1306: *
1307: * 1. "<subject>" [URL="<subject">];
1308: * 2. "<subject>" -> "<object>" [label="<predicate>",URL="<predicate>"];
1309: * 3. "<object>" [URL="<object>"];
1.4 barstow 1310: *
1311: *@param subj the subject
1312: *@param pred the predicate
1313: *@param obj the object (as a Resource)
1314: */
1315: public void statementDotResource(AResource subj, AResource pred, AResource obj)
1316: {
1317: if (this.pw == null) return;
1318:
1.12 barstow 1319: printFirstPart(subj);
1320:
1321: this.pw.print("\" -> ");
1.4 barstow 1322:
1.7 barstow 1323: if (obj.isAnonymous()) {
1.12 barstow 1324: if (this.anonNodesEmpty) {
1.14 barstow 1325: this.pw.println("\"" + ANON_NODE +
1.15 barstow 1326: obj.getAnonymousID() +
1327: "\" [label=\"" + pred.getURI() + "\",URL=\"" +
1328: pred.getURI() + "\"];");
1.12 barstow 1329: } else {
1.15 barstow 1330: this.pw.println("\"" + ANON_NODE + obj.getAnonymousID() +
1331: "\" [label=\"" + pred.getURI() + "\",URL=\"" +
1332: pred.getURI() + "\"];");
1.12 barstow 1333: }
1.7 barstow 1334: } else {
1.14 barstow 1335: this.pw.println("\"" + obj.getURI() + "\" [label=\"" +
1336: pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];");
1.12 barstow 1337: this.pw.println("\"" + obj.getURI() + "\" [URL=\"" +
1338: obj.getURI() + "\"];");
1.14 barstow 1339: }
1.4 barstow 1340: }
1341:
1342: /*
1343: * Handler for a Resource/Resource/Literal triple (S/P/O).
1344: * Outputs the given triple using Dot syntax.
1.12 barstow 1345: *
1346: * Each triple will be output in three lines of DOT code as
1347: * follows (not including the complication of anon nodes
1348: * and the possiblity that the anon nodes may be named
1349: * with an empty string):
1350: *
1351: * 1. "<subject>" [URL="<subject">];
1352: * 2. "<subject>" -> "<literal>" [label="<predicate>",URL="<predicate>"];
1353: * 3. "<literal>" [shape="box"];
1.4 barstow 1354: *
1355: *@param subj the subject
1356: *@param pred the predicate
1357: *@param obj the object (as a Literal)
1358: */
1359: public void statementDotLiteral(AResource subj, AResource pred, ALiteral lit)
1360: {
1361: if (this.pw == null) return;
1362:
1.12 barstow 1363: printFirstPart(subj); // Same as Res/Res/Res
1.4 barstow 1364:
1365: /*
1366: * Before outputing the object (Literal) do the following:
1367: *
1368: * o GraphViz/DOT cannot handle embedded line terminators characters
1369: * so they must be replaced with spaces
1370: * o Limit the number of chars to make the graph legible
1371: * o Escape double quotes
1372: */
1373: String s1 = new String(lit.toString());
1374: s1 = s1.replace('\n', ' ');
1375: s1 = s1.replace('\f', ' ');
1376: s1 = s1.replace('\r', ' ');
1377: if (s1.indexOf('"') != -1)
1378: s1 = replaceString(s1, "\"", "\\\"");
1379:
1380: // Anything beyond 80 chars makes the graph too large
1381: String tmpObject;
1382: if (s1.length() >= 80)
1383: tmpObject = s1.substring(0, 80) + " ...";
1384: else
1385: tmpObject = s1.substring(0, s1.length());
1386:
1.13 barstow 1387: // Create a temporary label for the literal so that if
1388: // it is duplicated it will be unique in the graph and
1389: // thus have its own node.
1390: String tmpName = "Literal_" + Integer.toString(this.numLiterals);
1391: this.pw.print("\" -> \"" + tmpName);
1.4 barstow 1392:
1.14 barstow 1393: this.pw.println("\" [label=\"" + pred.getURI() +
1394: "\",URL=\"" + pred.getURI() + "\"];");
1.4 barstow 1395:
1.13 barstow 1396: this.pw.println("\"" + tmpName + "\" [shape=box,label=\"" + tmpObject + "\"];");
1.4 barstow 1397: }
1398: }
1399:
1.5 barstow 1400: private void printErrorMessages(ServletOutputStream out,
1401: SaxErrorHandler eh)
1402: {
1403: try {
1404: String s;
1405:
1406: s = eh.getFatalErrors();
1407: if (s != null && s.length() >= 1)
1408: out.println("<h2>Fatal Error Messages</h2>" + s);
1409:
1410: s = eh.getErrors();
1411: if (s != null && s.length() >= 1)
1412: out.println("<h2>Error Messages</h2>" + s);
1413:
1414: s = eh.getWarnings();
1415: if (s != null && s.length() >= 1)
1416: out.println("<h2>Warning Messages</h2>" + s);
1417: } catch (Exception e) {
1418: System.err.println(SERVLET_NAME + ": Error printing error messages.");
1419: }
1420: }
1421:
1422: /*
1423: * Initialize the graph output file. If an error occurs, this
1424: * function will print an error message.
1425: *
1426: *@param out the servlet's output stream
1427: *@req the servlet request object
1428: *@return the File object for the graph file; null if an error occurs
1429: */
1.4 barstow 1430: private File initGraphFile(ServletOutputStream out,
1431: HttpServletRequest req)
1432: {
1433: try {
1434: // Stop if any of the parameters are missing
1435: if (m_ServletTmpDir == null ||
1436: m_GraphVizPath == null ||
1.16 barstow 1437: m_GraphVizFontDir == null)
1.4 barstow 1438: {
1439: // Put the paths in a comment in the returned content
1440: out.println("<!-- SERVLET_TMP_DIR = " + m_ServletTmpDir);
1441: out.println("GRAPH_VIZ_PATH = " + m_GraphVizPath);
1442: out.println("GRAPH_FONT_DIR = " + m_GraphVizFontDir + " -->");
1443:
1.12 barstow 1444: out.println("<h1>Servlet initialization failed</h1>");
1445: out.println("Please send a message to <a href='mailto:" + MAIL_TO + "'>" + MAIL_TO + "</a> and mention this problem.");
1.4 barstow 1446: return null;
1447: }
1448: } catch (Exception e) {
1449: System.err.println("Unable to create a temporary graph file. A graph cannot be generated.");
1450: return null;
1451: }
1452:
1453: File dotFile = null;
1454:
1455: try {
1456: // Must generate a unique file name that the DOT handler will use
1457: dotFile = createTempFile(m_ServletTmpDir, TMP_FILE_PREFIX, SUFFIX_DOT);
1458: if (dotFile == null) {
1459: out.println("<h1>Failed to create a temporary graph file. A graph cannot be generated.</h1>");
1460: return null;
1461: }
1462:
1463: } catch (IOException ioe) {
1464: try {
1465: out.println("<h1>Unable to create a temporary graph file. A graph cannot be generated.</h1>");
1466: } catch (Exception e2) {
1467: System.err.println("Unable to create a temporary graph file. A graph cannot be generated.");
1468: }
1469: }
1470:
1471: return dotFile;
1.1 barstow 1472: }
1.6 barstow 1473:
1474: /*
1475: * Check if the given URI is supported or not
1476: *
1477: *@param out the servlet's output stream
1478: *@param uri the URI to check
1479: *@return true if the URI is supported; false otherwise
1480: */
1481: private boolean isURISupported(ServletOutputStream out, String uri)
1482: {
1483: try {
1484: if (uri.length() >= 4 && uri.substring(0,4).equalsIgnoreCase("file")) {
1485: out.println("<h1>file URI Schemes are NOT Supported</h1>");
1486: out.println("URIs from the 'file' URI scheme are not supported by this servlet.");
1487: return false;
1488: }
1489: } catch (Exception e) {
1490: System.err.println("Exception in isURISupported.");
1491: return false;
1492: }
1493:
1494: return true;
1495: }
1.1 barstow 1496:
1497: /*
1498: * Handle the servlets doGet or doPut request
1499: *
1500: *@param req the servlet's request
1501: *@param res the servlet's response
1502: *@throws SevletException, IOException
1503: */
1504: private void process(HttpServletRequest req, HttpServletResponse res,
1505: String sRDF, String sURI) throws ServletException, IOException
1506: {
1507: ServletOutputStream out = res.getOutputStream ();
1508:
1.10 barstow 1509: res.setContentType ("text/html");
1510:
1.12 barstow 1511: String sSaveRDF = req.getParameter (SAVE_RDF);
1512: String sSaveDOTFile = req.getParameter (SAVE_DOT_FILE);
1513: String sFormat = req.getParameter (FORMAT);
1514: String sNTriples = req.getParameter (NTRIPLES);
1515: String sEmbedded = req.getParameter (EMBEDDED_RDF);
1516: String sTriplesAndGraph = req.getParameter (TRIPLES_AND_GRAPH);
1517: String sAnonNodesEmpty = req.getParameter (ANON_NODES_EMPTY);
1518:
1519: // Set the print flags
1520: boolean printTriples = true;
1521: boolean printGraph = true;
1522: if (sTriplesAndGraph != null) {
1523: if (sTriplesAndGraph.equals(PRINT_TRIPLES))
1524: printGraph = false;
1525: if (sTriplesAndGraph.equals(PRINT_GRAPH))
1526: printTriples = false;
1527: }
1.1 barstow 1528:
1.12 barstow 1529: // Determine if printing the triples and/or graph
1530: boolean anonNodesEmpty = (sAnonNodesEmpty != null) ? true : false;
1.1 barstow 1531: boolean nTriples = (sNTriples != null) ? true : false;
1.12 barstow 1532:
1.10 barstow 1533: // ARP parser has embedded = true by default so if user
1534: // wants embedding, must set it to false
1535: boolean embedded = (sEmbedded != null) ? false : true;
1.1 barstow 1536:
1537: String sError = null;
1538:
1539: InputStream in = null;
1540: String xmlBase = DEFAULT_NAMESPACE;
1541:
1542: printDocumentHeader (out);
1543:
1544: if (sURI != null && sURI.length() >= 1) {
1.6 barstow 1545:
1546: // First check for unsupported URIs
1547: if (!isURISupported(out, sURI)) {
1548: printDocumentFooter(out, null);
1549: return;
1550: }
1551:
1.1 barstow 1552: xmlBase = sURI;
1553: try {
1554: File ff = new File(sURI);
1555: in = new FileInputStream(ff);
1.6 barstow 1556: } catch (Exception ignore) {
1.1 barstow 1557: try {
1558: URL url;
1559: url=new URL(sURI);
1560: in = url.openStream();
1561: sRDF = getByteStream(sURI);
1562: if (sRDF == null)
1.6 barstow 1563: sError = "error";
1.1 barstow 1564: } catch (Exception e) {
1.6 barstow 1565: sError = "error";
1.1 barstow 1566: }
1567: }
1568: }
1569:
1570: if (sError != null) {
1.6 barstow 1571: out.println("<h1>RDF Load Error</h1>");
1572: out.println("An attempt to load the RDF from URI '" + sURI + "' failed. (The URI may not exist or the server is down.)");
1.1 barstow 1573: printDocumentFooter(out, null);
1574: return;
1575: }
1.4 barstow 1576:
1577: PrintWriter pw = null; // The writer for the graph file
1578: File dotFile = null; // The graph file
1.12 barstow 1579: if (sFormat != null && printGraph) {
1.4 barstow 1580: dotFile = initGraphFile(out, req);
1581: if (dotFile == null)
1582: // Assume error has been reported
1583: return;
1584:
1585: // Create a PrintWriter for the DOT handler
1586: FileWriter fw = new FileWriter(dotFile);
1587: if (fw != null)
1588: pw = new PrintWriter(fw);
1589: if (pw != null)
1590: // Add the graph header
1591: processGraphParameters (req, pw);
1592: }
1593:
1594: // Create the StatementHandler - it will handle triples for
1595: // the table/ntriples and the graph file
1.12 barstow 1596: SH sh = new SH(out, pw, nTriples, printTriples, printGraph, anonNodesEmpty);
1.4 barstow 1597:
1598: // Create the ErrorHandler
1599: SaxErrorHandler errorHandler = new SaxErrorHandler(out, false);
1600:
1601: // Create and initialize the parser
1602: ARP parser = new com.hp.hpl.jena.rdf.arp.ARP();
1603: parser.setErrorHandler(errorHandler);
1604: parser.setStatementHandler(sh);
1.10 barstow 1605: parser.setEmbedding(embedded);
1.1 barstow 1606:
1607: printListing (out, sRDF, sURI != null && sURI.length() >= 1);
1.12 barstow 1608:
1609: if (printTriples)
1610: printTripleTableHeader (out, nTriples);
1.1 barstow 1611:
1612: try {
1613: if (sURI != null && sURI.length() >= 1) {
1614: parser.load(in, xmlBase);
1615: } else {
1616: StringReader sr = new StringReader (sRDF);
1617: parser.load(sr, xmlBase);
1618: }
1619: } catch (IOException ioe) {
1620: sError = "IOError parsing: " + sURI + ": " + ioe.toString();
1621: } catch (Exception ex) {
1622: sError = "Exception parsing: " + sURI + ": " + ex.toString();
1623: }
1624:
1.12 barstow 1625: if (printTriples)
1626: printTripleTableFooter(out, nTriples);
1.5 barstow 1627:
1628: printErrorMessages(out, errorHandler);
1.1 barstow 1629:
1630: if (sError != null) {
1.6 barstow 1631: out.println ("<h1>Parser Loading Error</h1>");
1632: out.println (sError);
1.1 barstow 1633: printDocumentFooter(out, null);
1634: return;
1635: }
1636:
1.10 barstow 1637: res.flushBuffer();
1.12 barstow 1638: if (sFormat != null && printGraph) {
1.4 barstow 1639: generateGraph(out, pw, dotFile, sRDF, req, sFormat,
1.1 barstow 1640: (sSaveRDF != null) ? true : false,
1641: (sSaveDOTFile != null && sSaveDOTFile.equals ("on") ? true : false));
1642: }
1643:
1644:
1.9 barstow 1645: if (sURI != null && sURI.length() >= 1)
1646: printDocumentFooter(out, null);
1647: else
1648: printDocumentFooter(out, sRDF);
1.1 barstow 1649: }
1650: }
Webmaster