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