Annotation of java/classes/org/w3c/rdf/examples/ARPServlet.java, revision 1.76
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.55 duerst 66: * URI - the URI of the RDF to validate
67: *
68: * PARSE - if "Parse RDF", then parse RDF from the textarea;
1.65 duerst 69: * else download from URI; if not present, prefer URI,
70: * but if URI is empty, parse RDF (old behavior).
1.1 barstow 71: *
72: * ORIENTATION - the graph's orientation (left to right or top to
1.16 barstow 73: * bottom); default is left to right
1.1 barstow 74: *
1.16 barstow 75: * FONT_SIZE - the font size to use (10, 12, 14, 16 and 20 are
76: * supported); the default is 10
1.1 barstow 77: *
1.65 duerst 78: * NODE_COLOR - the color of nodes; default is black
79: *
80: * NODE_TEXT_COLOR - the color of the text in nodes; default is blue
81: *
82: * EDGE_COLOR - the color of edges; default is darkgreen
83: *
84: * EDGE_TEXT_COLOR - the color of the text on edges; default is red
85: *
1.16 barstow 86: * ANON_NODES_EMPTY - if "on", anonymous nodes are not labeled; otherwise
87: * anonymous nodes are labeled;
1.12 barstow 88: *
89: * TRIPLES_AND_GRAPH - support values are:
90: *
1.16 barstow 91: * PRINT_BOTH - display triples and a graph (the default)
92: * PRINT_TRIPLES - only display the triples
93: * PRINT_GRAPH - only display the graph
1.12 barstow 94: *
1.63 duerst 95: * FORMAT - the graph's output format. Supported values are:
1.1 barstow 96: *
1.65 duerst 97: * GIF_EMBED - embed the graph as a GIF
1.1 barstow 98: * GIF_LINK - don't embed the GIF but create a link for it
99: * SVG_LINK - create the graph in SVG format and create a link to the file
1.71 epietrig 100: * SVG_EMBED - create the graph in SVG format and embed it in an object tag
101: * ISV_ZVTM - IsaViz/ZVTM (Dynamic View - requires Java Plug-in 1.4)
1.1 barstow 102: * PNG_EMBED - create the graph in PNG format and embed the graph in the
1.65 duerst 103: * document that is returned (the default)
1.1 barstow 104: * PNG_LINK - create the graph in PNG format and create a link to the file
105: * PS_LINK - create a PostScript image of the file and a link to the file
106: * HP_PCL_LINK - create a HPGL/2 - PCL (Laserwriter) image of the file
107: * and a link to the file
108: * HP_GL_LINK - create a HPGL - PCL (pen plotter) image of the file and
109: * a link to the file
110: *
111: * NTRIPLES if "on" the tabular output will be in the NTriples format;
112: * otherwise a table of Subject, Predicate, Objects will be generated
113: *
1.16 barstow 114: ***********************************************************************
115: *
116: * Server Initialization - this servlet requires the following
117: * parameters be set in the servlet's init() method - via the
118: * ServletConfig object:
1.1 barstow 119: *
1.16 barstow 120: * GRAPH_VIZ_ROOT - the absolute path of the top-level directory containing
121: * GraphViz's binary distribution
122: *
1.68 duerst 123: * GRAPH_VIZ_PATH - absolute or relative (based on GRAPH_VIZ_ROOT) path of
1.16 barstow 124: * the DOT executable (e.g. dotneato/dot) - the program used to generate
125: * a graph from a DOT file.
126: *
1.68 duerst 127: * GRAPH_VIZ_FONT_DIR - absolute or relative (based on GRAPH_VIZ_ROOT) path of
1.16 barstow 128: * the fonts directory used by GraphViz (e.g. Fonts)
129: *
130: * SERVLET_TMP_DIR - the absolute path of the directory to be used to
131: * store temporary files used by the servlet and GraphViz. This
132: * directory must be writable by the servlet.
133: *
134: * NOTE - Some files created by the servlet are not removed by
135: * servlet (e.g. graph image files).
136: *
137: * If any of these parameters are not defined, the servlet will NOT
138: * validate the RDF.
139: *
140: ***********************************************************************
141: *
142: * Dependencies - this servlet requires the following Java packages
143: * as well as GraphViz (described above):
144: *
145: * ARP RDF parser: http://www.hpl.hp.co.uk/people/jjc/arp/download.html
146: *
147: * SAX-based XML parser: e.g. Xerces at http://xml.apache.org/
148: *
149: * Java servlet package: http://java.sun.com/products/servlet/archive.html
150: *
151: * Apache Regular Expression: http://jakarta.apache.org/builds/jakarta-regexp/release/v1.2/
152: *
153: ***********************************************************************
154: *
155: * Author: Art Barstow <barstow@w3.org>
1.30 duerst 156: * Author (internationalization): Martin J. Duerst <duerst@w3.org>
1.69 epietrig 157: * Author (maintenance): Emmanuel Pietriga <emmanuel@w3.org>
1.16 barstow 158: *
1.76 ! epietrig 159: * $Id: ARPServlet.java,v 1.75 2003/05/09 18:55:35 epietrig Exp $
1.16 barstow 160: *
161: ***********************************************************************/
1.1 barstow 162:
1.16 barstow 163: // http://dev.w3.org/cvsweb/java/classes/org/w3c/rdf/examples/
164: package org.w3c.rdf.examples;
1.1 barstow 165:
166: import java.io.*;
167: import java.net.MalformedURLException;
168: import java.net.URL;
1.33 duerst 169: import java.net.URLConnection;
1.1 barstow 170: import java.util.StringTokenizer;
171: import java.util.Enumeration;
1.14 barstow 172: import java.util.Hashtable;
1.16 barstow 173:
174: // http://java.sun.com/products/servlet/2.2/javadoc/javax/servlet/package-summary.html
175: import javax.servlet.*;
1.1 barstow 176: import javax.servlet.http.*;
1.32 duerst 177: import javax.mail.internet.ContentType;
1.1 barstow 178:
1.16 barstow 179: // http://xml.apache.org/apiDocs/org/xml/sax/package-summary.html
180: import org.xml.sax.InputSource;
1.69 epietrig 181: //import org.xml.sax.Parser;
1.1 barstow 182: import org.xml.sax.SAXException;
183: import org.xml.sax.SAXParseException;
184: import org.xml.sax.ErrorHandler;
185: import org.xml.sax.helpers.*;
186:
1.16 barstow 187: // http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html
1.3 barstow 188: import org.apache.regexp.RE;
1.53 duerst 189: import org.apache.regexp.RESyntaxException;
1.3 barstow 190:
1.16 barstow 191: // http://www.hpl.hp.co.uk/people/jjc/arp/apidocs/index.html
192: import com.hp.hpl.jena.rdf.arp.*;
1.1 barstow 193:
194: public class ARPServlet extends HttpServlet
195: {
1.76 ! epietrig 196: final static public String REVISION = "$Id: ARPServlet.java,v 1.75 2003/05/09 18:55:35 epietrig Exp $";
1.1 barstow 197:
198: // The email address for bug reports
1.6 barstow 199: private static final String MAIL_TO = "www-rdf-validator@w3.org";
1.1 barstow 200:
201: // Names of the POST parameters (described above) and their
1.12 barstow 202: // defaults (if applicable)
203: private static final String TEXT = "RDF";
204: private static final String SAVE_DOT_FILE = "SAVE_DOT_FILE";
205: private static final String SAVE_RDF = "SAVE_RDF";
206: private static final String EMBEDDED_RDF = "EMBEDDED_RDF";
207: private static final String URI = "URI";
1.55 duerst 208: private static final String PARSE = "PARSE";
1.12 barstow 209: private static final String NTRIPLES = "NTRIPLES";
210: private static final String ANON_NODES_EMPTY = "ANON_NODES_EMPTY";
1.1 barstow 211:
212: private static final String NODE_COLOR = "NODE_COLOR";
213: private static final String DEFAULT_NODE_COLOR = "black";
214:
215: private static final String NODE_TEXT_COLOR = "NODE_TEXT_COLOR";
1.65 duerst 216: private static final String DEFAULT_NODE_TEXT_COLOR = "blue";
1.1 barstow 217:
218: private static final String EDGE_COLOR = "EDGE_COLOR";
1.65 duerst 219: private static final String DEFAULT_EDGE_COLOR = "darkgreen";
1.1 barstow 220:
221: private static final String EDGE_TEXT_COLOR = "EDGE_TEXT_COLOR";
1.65 duerst 222: private static final String DEFAULT_EDGE_TEXT_COLOR = "red";
1.1 barstow 223:
224: private static final String ORIENTATION = "ORIENTATION";
1.65 duerst 225: private static final String DEFAULT_ORIENTATION = "LR"; // Left to Right
1.1 barstow 226:
227: private static final String FONT_SIZE = "FONT_SIZE";
228: private static final String DEFAULT_FONT_SIZE = "10";
229:
1.12 barstow 230: // Print graph and/or triples
231: private static final String TRIPLES_AND_GRAPH = "TRIPLES_AND_GRAPH";
232: private static final String PRINT_BOTH = "PRINT_BOTH";
233: private static final String PRINT_TRIPLES = "PRINT_TRIPLES";
234: private static final String PRINT_GRAPH = "PRINT_GRAPH";
235:
236: // Graph formats
1.1 barstow 237: private static final String FORMAT = "FORMAT";
238: private static final String FORMAT_GIF_EMBED = "GIF_EMBED";
239: private static final String FORMAT_GIF_LINK = "GIF_LINK";
240: private static final String FORMAT_SVG_LINK = "SVG_LINK";
1.71 epietrig 241: private static final String FORMAT_SVG_EMBED = "SVG_EMBED";
242: private static final String FORMAT_ISV_ZVTM = "ISV_ZVTM";
1.1 barstow 243: private static final String FORMAT_PNG_EMBED = "PNG_EMBED";
244: private static final String FORMAT_PNG_LINK = "PNG_LINK";
245: private static final String FORMAT_PS_LINK = "PS_LINK";
246: private static final String FORMAT_HP_PCL_LINK = "HP_PCL_LINK";
247: private static final String FORMAT_HP_GL_LINK = "HP_GL_LINK";
1.63 duerst 248: private static final String DEFAULT_FORMAT = "PNG_EMBED";
1.1 barstow 249:
250: // Fonts are not currently configurable
1.69 epietrig 251: private static final String DEFAULT_TTF_FONT = "cyberbit"; //could changed to 'arialuni'
252: private static final String DEFAULT_FONT = "Courier"; //could changed to 'arialuni' to get coverage for japanese/russian/...
1.1 barstow 253:
254: // Names of the servlet's parameters - for Jigsaw web server
255: private static final String SERVLET_TMP_DIR = "SERVLET_TMP_DIR";
256: private static final String GRAPH_VIZ_ROOT = "GRAPH_VIZ_ROOT";
257: private static final String GRAPH_VIZ_PATH = "GRAPH_VIZ_PATH";
258: private static final String GRAPH_VIZ_FONT_DIR = "GRAPH_VIZ_FONT_DIR";
259:
260: // Variables for the servlet's parameters
261: private static String m_ServletTmpDir = null;
262: private static String m_GraphVizPath = null;
263: private static String m_GraphVizFontDir = null;
264:
1.30 duerst 265: // Names of environment variable needed by GraphVis
1.1 barstow 266: private static String DOTFONTPATH = "DOTFONTPATH";
267: private static String LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
268:
269: // Names used for temporary files
270: private static final String TMP_FILE_PREFIX = "servlet_";
271: private static final String SUFFIX_TMP_DIR = ".tmp";
272: private static final String SUFFIX_DOT = ".dot";
273: private static final String SUFFIX_RDF = ".rdf";
274:
275: // Names used for file suffixes and for GraphViz's command line
276: // option
277: private static final String NAME_GIF = "gif";
278: private static final String NAME_HPGL = "hpgl";
279: private static final String NAME_PCL = "pcl";
280: private static final String NAME_PNG = "png";
281: private static final String NAME_PS = "ps";
282: private static final String NAME_SVG = "svg";
283:
284: // Default GraphViz parameter names and their default values
285: // Servlet name
286: private static final String SERVLET_NAME = "ARPServlet";
287:
288: // Name for the DOT file title
289: private static final String DOT_TITLE = "dotfile";
290:
1.30 duerst 291: // The string to use to prefix anonymous nodes.
1.14 barstow 292: private static final String ANON_NODE = "genid:";
293:
1.1 barstow 294: // The string to use for a namespace name when no
295: // namespace is available - e.g. for the RDF that is
296: // directly entered into the input form.
1.69 epietrig 297: private static final String DEFAULT_NAMESPACE = "";
1.1 barstow 298:
1.72 epietrig 299: //used to detect whether the provided document contains at least one triple, or if it is not RDF at all
300: //necessary because ARP does not report any error when parsing an XML document which does not contain any
301: //RDF statement
302: static boolean AT_LEAST_ONE_TRIPLE=false;
303:
1.71 epietrig 304: //colors for ISV-plugin texts (resources, properties and literals)
305: private static float resTBh=0.33333334f;
306: private static float resTBs=0.37142858f;
307: private static float resTBv=0.4117647f;
308: private static float prpTh=0.6680911f;
309: private static float prpTs=0.56796116f;
310: private static float prpTv=0.80784315f;
311: private static float litTBh=0.12878788f;
312: private static float litTBs=0.5f;
313: private static float litTBv=0.5176471f;
314:
1.53 duerst 315: // exception used by getRDFfromURI
316: private class getRDFException extends Exception {
317: public getRDFException (String s) {
318: super (s);
319: }
320: }
321:
1.1 barstow 322: /*
1.14 barstow 323: * Create a File object from the given directory and file names
1.1 barstow 324: *
325: *@param directory the file's directory
326: *@param prefix the file's prefix name (not its directory)
327: *@param suffix the file's suffix or extension name
328: *@return a File object if a temporary file is created; null otherwise
329: */
1.4 barstow 330: private File createTempFile (String directory, String prefix, String suffix)
331: {
1.1 barstow 332: File f;
333: try {
334: File d = new File(directory);
335: f = File.createTempFile(prefix, suffix, d);
336: } catch (Exception e) {
337: return null;
338: }
339: return f;
340: }
341:
342: /*
343: * Given a URI string, open it, read its contents into a String
344: * and return the String
345: *
346: *@param uri the URI to open
347: *@return the content at the URI or null if any error occurs
348: */
1.53 duerst 349: private String getRDFfromURI (String uri) throws getRDFException
1.4 barstow 350: {
1.53 duerst 351: /* add something like this code here, to allow reading from a file:
352: (if we really want to allow this!)
353: File ff = new File(uri);
354: in = new FileInputStream(ff);
355: */
356: URL url = null;
357: try {
358: url = new URL(uri);
359: } catch (MalformedURLException e) {
360: throw new getRDFException("Malformed URI.");
361: }
362:
363: URLConnection con = null;
364: try {
365: con = url.openConnection();
366: con.setRequestProperty("Accept", "application/rdf+xml");
367: con.connect();
368: } catch (Exception e) {
369: throw new getRDFException("Unable to open connection.");
370: }
371: String contentT = con.getContentType();
372: String HTTPcharset = null;
373: if (contentT != null) {
374: ContentType contentType = null;
375: try {
376: contentType = new ContentType(con.getContentType());
377: } catch (javax.mail.internet.ParseException e) {
378: throw new getRDFException("Unparsable content type.");
1.32 duerst 379: }
1.53 duerst 380: HTTPcharset = contentType.getParameter("charset");
381: }
382:
383: // need buffer for lookahead for encoding detection
384: BufferedInputStream bis = null;
385: try {
386: bis = new BufferedInputStream(con.getInputStream());
387: } catch (IOException e) {
388: throw new getRDFException("Cannot open stream.");
389: }
390: bis.mark(200); // mark start so that we can get back to it
391: String s = "";
392:
1.54 duerst 393: try { // read start of file as bytes
394: int c;
395: int numRead = 0;
1.53 duerst 396: while ((c = bis.read()) != -1) {
397: s += (char)c;
1.54 duerst 398: if (numRead++ >= 195) break;
1.53 duerst 399: }
400: } catch (IOException e) {
401: throw new getRDFException("IOException while starting reading.");
402: }
403:
404: if (s.equals(""))
405: // Nothing was returned
406: throw new getRDFException("Empty document, ignored.");
407:
408: // A server could return content but not the RDF/XML that
409: // we need. Check the beginning of s and if it looks like
410: // a generic HTML message, return an error.
411: if (s.startsWith("<!DOCTYPE"))
412: throw new getRDFException("Document looks like HTML, ignored.");
1.54 duerst 413:
414: String APPFcharset = null; // 'charset' according to XML APP. F
415: int ignoreBytes = 0;
416: if (s.startsWith("\u00FE\u00FF")) {
417: APPFcharset = "UTF-16BE";
418: ignoreBytes = 2;
419: }
420: else if (s.startsWith("\u00FF\u00FE")) {
421: APPFcharset = "UTF-16LE";
422: ignoreBytes = 2;
423: }
424: else if (s.startsWith("\u00EF\u00BB\u00BF")) {
425: APPFcharset = "UTF-8";
426: ignoreBytes = 3;
427: }
428: else if (s.startsWith("\u0000<\u0000?")) {
429: APPFcharset = "UTF-16BE";
430: }
431: else if (s.startsWith("<\u0000?\u0000")) {
432: APPFcharset = "UTF-16LE";
433: }
434: else if (s.startsWith("<?xml")) {
1.69 epietrig 435: APPFcharset = "iso-8859-1"; //to not loose any bytes
1.54 duerst 436: }
437: else if (s.startsWith("\u004C\u006F\u00A7\u0094")) {
438: APPFcharset = "CP037"; // EBCDIC
439: }
1.69 epietrig 440: else {
441: APPFcharset = "iso-8859-1"; //to not loose any bytes
442: }
443:
1.54 duerst 444: // convert start of xml input according to APPFcharset
445: String xmlstart = null;
446: try {
1.69 epietrig 447: // System.err.println("---------------------------");
448: // System.err.println("ignoreBytes="+ignoreBytes);
449: // System.err.println("s="+s);
450: // System.err.println("APPFcharset="+APPFcharset);
451: // if (APPFcharset!=null){xmlstart = new String(s.substring(ignoreBytes).getBytes("iso-8859-1"), APPFcharset);}
452: // else {xmlstart=new String(s.substring(ignoreBytes).getBytes("iso-8859-1"));APPFcharset = "UTF-8";}
1.54 duerst 453: xmlstart = new String(s.substring(ignoreBytes).getBytes("iso-8859-1"), APPFcharset);
454: } catch (UnsupportedEncodingException e) {
455: throw new getRDFException("Unsupported encoding '"+APPFcharset+"'.");
456: }
457: RE r;
458: try {
459: r = new RE("<\\?xml[ \\t\\n\\r]+version[ \\t\\n\\r]?=[ \\t\\n\\r]?(['\"])([a-zA-Z0-9_:]|\\.|-)+\\1[ \\t\\n\\r]+encoding[ \\t\\n\\r]?=[ \\t\\n\\r]?(['\"])([A-Za-z]([A-Za-z0-9._]|-)*)\\3");
460: } catch (RESyntaxException res) {
461: throw new getRDFException("Wrong regular expression syntax.");
462: }
463: // r.setMatchFlags(MATCH_NORMAL | MATCH_SINGLELINE);
464: String XMLcharset = null;
465: if (r.match(xmlstart) && r.getParenStart(0)==0)
466: XMLcharset = r.getParen(4);
467: if (HTTPcharset != null)
468: HTTPcharset = HTTPcharset.toUpperCase();
469: if (XMLcharset != null)
470: XMLcharset = XMLcharset.toUpperCase();
471:
472: String finalCharset = null;
473: if (HTTPcharset != null) {
474: if (XMLcharset != null && !HTTPcharset.equals(XMLcharset))
475: throw new getRDFException("Charset conflict: Content-Type: "
476: + contentT+ ". XML encoding: " + XMLcharset + ".");
477: finalCharset = HTTPcharset;
478: }
479: else if (XMLcharset != null)
480: finalCharset = XMLcharset;
481: if ((finalCharset != null && finalCharset.equals("UTF-16")) ||
482: (finalCharset == null && APPFcharset.startsWith("UTF-16")))
483: if (ignoreBytes == 2)
484: finalCharset = APPFcharset; // use correct endianness
485: else
486: throw new getRDFException("Illegal XML: UTF-16 without BOM.");
487: if (finalCharset == null)
488: finalCharset = "UTF-8";
489:
490: try {
491: bis.reset(); // move back to start of stream
492: bis.skip(ignoreBytes); // skip BOM
493: } catch (IOException e) {
494: throw new getRDFException("IOException while resetting stream.");
495: }
496:
497: InputStreamReader isr = null;
498: try {
499: isr = new InputStreamReader(bis, finalCharset);
500: } catch (UnsupportedEncodingException e) {
501: throw new getRDFException("Unsupported encoding '"+finalCharset+"'.");
502: }
1.76 ! epietrig 503: StringBuffer sb=new StringBuffer("");
! 504: int bytenum=0;
! 505: try {// read whole file as characters
1.54 duerst 506: int c;
507: while ((c = isr.read()) != -1) {
508: sb.append((char)c);
1.76 ! epietrig 509: bytenum++;
1.54 duerst 510: }
1.76 ! epietrig 511: }
! 512: catch (IOException e){
! 513: throw new getRDFException("Undecodable data when reading URI at byte "+bytenum+" using encoding '"+finalCharset+"'."+" Please check encoding and encoding declaration of your document.");
1.54 duerst 514: }
1.76 ! epietrig 515: // todo: fix encoding parameter in xml pseudo-PI
1.54 duerst 516: return sb.toString();
1.1 barstow 517: }
518:
519: /*
1.4 barstow 520: * Copy the given string of RDF to a file in the given directory.
521: * This is only done if the servlet is explictly asked to save
522: * the RDF to a file.
1.1 barstow 523: *
1.14 barstow 524: *@param tmpDir the file's directory
1.1 barstow 525: *@param rdf the string of RDF
526: */
527: private void copyRDFStringToFile(String tmpDir, String rdf)
528: {
529: try {
530: // Generate a unique file name
531: File tmpFile = createTempFile(tmpDir, TMP_FILE_PREFIX, SUFFIX_RDF);
532: if (tmpFile == null) {
533: // Not really a critical error, just return
534: return;
535: }
536:
537: // Create a PrintWriter for the GraphViz consumer
538: FileWriter fw = new FileWriter(tmpFile);
539: PrintWriter pw = new PrintWriter(fw);
540:
541: pw.println(rdf);
542: pw.close();
543: } catch (Exception e) {
1.4 barstow 544: System.err.println(SERVLET_NAME + ": error occured trying to save RDF to file '" + tmpDir + TMP_FILE_PREFIX + SUFFIX_RDF + "'.");
1.1 barstow 545: return;
546: }
547: }
548:
549: /*
550: * Given the graph's format option, return either the corresponding
551: * command line option for that option or the file name suffix for
552: * the graph option. For example GIF files have ".gif" for its
553: * suffix and GraphViz uses "-Tgif" for the command line.
554: *
1.69 epietrig 555: * NOTE: default is PNG.
1.1 barstow 556: *
557: *@param graphFormat the graph's output format
558: *@param suffix. If true, the name returned is for the graph's
559: * file name suffix; otherwise, the name returned is for the
560: * graph's command line option.
561: *@return the suffix to use for the graph's output file
562: */
563: private String getFormatName(String graphFormat, boolean suffix) {
564:
565: String name = (suffix) ? "." : "-T";
566:
1.4 barstow 567: if (graphFormat.equals(FORMAT_PNG_EMBED)) return name + NAME_PNG;
568: if (graphFormat.equals(FORMAT_PNG_LINK)) return name + NAME_PNG;
1.69 epietrig 569: if (graphFormat.equals(FORMAT_GIF_EMBED)) return name + NAME_GIF;
570: if (graphFormat.equals(FORMAT_GIF_LINK)) return name + NAME_GIF;
1.4 barstow 571: if (graphFormat.equals(FORMAT_SVG_LINK)) return name + NAME_SVG;
1.71 epietrig 572: if (graphFormat.equals(FORMAT_SVG_EMBED)) return name + NAME_SVG;
573: if (graphFormat.equals(FORMAT_ISV_ZVTM)) return name + NAME_SVG;
1.4 barstow 574: if (graphFormat.equals(FORMAT_PS_LINK)) return name + NAME_PS;
575: if (graphFormat.equals(FORMAT_HP_GL_LINK)) return name + NAME_HPGL;
1.1 barstow 576: if (graphFormat.equals(FORMAT_HP_PCL_LINK)) return name + NAME_PCL;
577:
1.69 epietrig 578: return name + NAME_PNG;
1.1 barstow 579: }
580:
581: /*
582: * Invokes the GraphVis program to create a graph image from the
583: * the given DOT data file
584: *
585: *@param dotFileName the name of the DOT data file
586: *@param outputFileName the name of the output data file
1.14 barstow 587: *@param graphFormat the graph's format
1.1 barstow 588: *@return true if success; false if any failure occurs
589: */
1.8 barstow 590: private boolean generateGraphFile(String dotFileName,
1.4 barstow 591: String outputFileName, String graphFormat)
592: {
1.16 barstow 593: String environment[] = {DOTFONTPATH + "=" + m_GraphVizFontDir};
1.1 barstow 594:
595: String formatOption = getFormatName(graphFormat, false);
596:
597: String cmdArray[] = {m_GraphVizPath, formatOption, "-o", outputFileName, dotFileName};
598: Runtime rt = Runtime.getRuntime();
599: try {
600: Process p = rt.exec(cmdArray, environment);
601: p.waitFor();
1.10 barstow 602:
1.1 barstow 603: } catch (Exception e) {
604: System.err.println("Error: generating OutputFile.");
605: return false;
606: }
607: return true;
608: }
609:
610: /*
611: * Returns a parameter from a request or the parameter's default
612: * value.
613: *
614: *@param req a Servlet request
1.14 barstow 615: *@param param the name of the parameter
616: *@param defString the string returned if the param is not found
1.1 barstow 617: *@return if the request contains the specfied parameter its value
618: * in the request is returned; otherwise its default value is
619: * returned
620: */
621: private String getParameter(HttpServletRequest req, String param,
622: String defString)
623: {
624: String s = req.getParameter(param);
625: return (s == null) ? defString : s;
626: }
627:
628: /*
629: * If the request contains any graph-related parameters, pass them
630: * to the graph consumer for handling
631: *
632: *@param req the response
1.14 barstow 633: *@param pw the PrintWriter
1.1 barstow 634: *@param consumer the GraphViz consumer
1.69 epietrig 635: *@param bitmap true=generate a bitmap (GIF or PNG), false=generate PostScript, SVG, etc.
1.1 barstow 636: */
1.69 epietrig 637: private void processGraphParameters (HttpServletRequest req, PrintWriter pw,boolean bitmap)
1.1 barstow 638: {
1.4 barstow 639: // Print the graph header
640: pw.println("digraph " + DOT_TITLE + "{ " );
1.1 barstow 641:
642: // Look for colors
1.4 barstow 643: String nodeColor = getParameter(req, NODE_COLOR,
644: DEFAULT_NODE_COLOR);
645: String nodeTextColor = getParameter(req, NODE_TEXT_COLOR,
646: DEFAULT_NODE_TEXT_COLOR);
647: String edgeColor = getParameter(req, EDGE_COLOR,
648: DEFAULT_EDGE_COLOR);
649: String edgeTextColor = getParameter(req, EDGE_TEXT_COLOR,
650: DEFAULT_EDGE_TEXT_COLOR);
651: String fontSize = getParameter(req, FONT_SIZE,
652: DEFAULT_FONT_SIZE);
1.1 barstow 653:
1.65 duerst 654: // Orientation must be either LR or TB
1.1 barstow 655: String orientation = req.getParameter (ORIENTATION);
1.65 duerst 656: if (orientation == null || !orientation.equals("TB"))
1.1 barstow 657: orientation = DEFAULT_ORIENTATION;
658:
659: // Add an attribute for all of the graph's nodes
1.69 epietrig 660: pw.println("node [fontname=\"" + ((bitmap) ? DEFAULT_TTF_FONT : DEFAULT_FONT) +
661: "\",fontsize=" + fontSize +
1.7 barstow 662: ",color=" + nodeColor +
1.12 barstow 663: ",fontcolor=" + nodeTextColor + "];");
1.1 barstow 664:
665: // Add an attribute for all of the graph's edges
1.69 epietrig 666: pw.println("edge [fontname=\"" + ((bitmap) ? DEFAULT_TTF_FONT : DEFAULT_FONT) +
667: "\",fontsize=" + fontSize +
1.8 barstow 668: ",color=" + edgeColor +
669: ",fontcolor=" + edgeTextColor + "];");
1.1 barstow 670:
671: // Add an attribute for the orientation
672: pw.println("rankdir=" + orientation + ";");
673: }
674:
675: private static class SaxErrorHandler implements org.xml.sax.ErrorHandler
676: {
1.22 duerst 677: PrintWriter out;
1.1 barstow 678: boolean silent = false;
1.5 barstow 679: String fatalErrors = "";
680: String errors = "";
681: String warnings = "";
1.69 epietrig 682: String datatypeErrors="";
1.1 barstow 683:
684: /*
685: * Constructuor for a SaxErrorHandler
686: *
1.22 duerst 687: *@param out the servlet's PrintWriter
1.1 barstow 688: *@param silent if false, output is suprressed
689: */
1.22 duerst 690: public SaxErrorHandler(PrintWriter out, boolean silent)
1.1 barstow 691: {
692: this.out = out;
693: this.silent = silent;
694: }
695:
696: /*
697: * Create a formatted string from the exception's message
698: *
1.5 barstow 699: *@param e the SAX Parse Exception
1.1 barstow 700: *@return a formatted string
701: */
702: private static String format(org.xml.sax.SAXParseException e)
703: {
704: String msg = e.getMessage();
705: if (msg == null)
706: msg = e.toString();
1.70 epietrig 707: msg = replaceString(msg,"&","&");
708: msg = replaceString(msg,"<","<");
709: msg = replaceString(msg,">",">");
710: msg = replaceString(msg,"\"",""");
1.71 epietrig 711: msg = replaceString(msg,"'","'");
1.1 barstow 712: return msg + "[Line = " + e.getLineNumber() + ", Column = " + e.getColumnNumber() + "]";
713: }
714:
715: /*
716: * Handle a parse error
717: *
1.5 barstow 718: *@param e the SAX Parse Exception
1.1 barstow 719: */
720: public void error(org.xml.sax.SAXParseException e)
721: throws org.xml.sax.SAXException
722: {
723: if (this.silent) return;
724:
1.69 epietrig 725: if (e instanceof com.hp.hpl.jena.rdf.arp.ParseException){
726: com.hp.hpl.jena.rdf.arp.ParseException pe=(com.hp.hpl.jena.rdf.arp.ParseException)e;
1.71 epietrig 727: // if (pe.getErrorNumber()==com.hp.hpl.jena.rdf.arp.ARP.WARN_NOT_SUPPORTED && pe.getMessage().indexOf("datatyping")!=-1){
728: // datatypeErrors+=String.valueOf(pe.getLineNumber())+", ";
729: // }
730: // else {
1.69 epietrig 731: this.errors += "Error: " + format(e) + "<br />";
1.71 epietrig 732: // }
1.69 epietrig 733: }
734: else {this.errors += "Error: " + format(e) + "<br />";}
1.1 barstow 735: }
736:
737: /*
738: * Handle a fatal parse error
739: *
1.5 barstow 740: *@param e the SAX Parse Exception
1.1 barstow 741: */
742: public void fatalError(org.xml.sax.SAXParseException e)
743: throws org.xml.sax.SAXException
744: {
745: if (this.silent) return;
746:
1.5 barstow 747: this.fatalErrors += "FatalError: " + format(e) + "<br />";
1.1 barstow 748: }
749:
750: /*
751: * Handle a parse warning
752: *
1.5 barstow 753: *@param e the SAX Parse Exception
1.1 barstow 754: */
755: public void warning(org.xml.sax.SAXParseException e)
756: throws org.xml.sax.SAXException
757: {
758: if (this.silent) return;
759:
1.69 epietrig 760: if (e instanceof com.hp.hpl.jena.rdf.arp.ParseException){
1.71 epietrig 761: // com.hp.hpl.jena.rdf.arp.ParseException pe=(com.hp.hpl.jena.rdf.arp.ParseException)e;
762: // if (pe.getErrorNumber()==com.hp.hpl.jena.rdf.arp.ARP.WARN_NOT_SUPPORTED && pe.getMessage().indexOf("datatyping")!=-1){
763: // datatypeErrors+=String.valueOf(pe.getLineNumber())+", ";
764: // }
765: // else {
1.69 epietrig 766: this.warnings += "Warning: " + format(e) + "<br />";
1.71 epietrig 767: // }
1.69 epietrig 768: }
1.71 epietrig 769: else {this.errors += "Warning: " + format(e) + "<br />";}
1.1 barstow 770: }
1.5 barstow 771:
772: /*
773: * Return the error messages
774: *
775: *@return the error messages or an empty string if there are
776: * no messages
777: */
778: public String getErrors()
779: {
780: return this.errors;
781: }
782:
1.69 epietrig 783: public String getDatatypeErrors()
784: {
785: return this.datatypeErrors;
786: }
787:
1.5 barstow 788: /*
789: * Return the fatal error messages
790: *
791: *@return the fatal error messages or an empty string if there are
792: * no messages
793: */
794: public String getFatalErrors()
795: {
796: return this.fatalErrors;
797: }
798:
799: /*
800: * Return the warning messages
801: *
802: *@return the warning messages or an empty string if there are
803: * no messages
804: */
805: public String getWarnings()
806: {
807: return this.warnings;
808: }
1.1 barstow 809: }
810:
811: /*
812: * Generate a graph of the RDF data model
813: *
1.64 duerst 814: *@param out the servlet's output Writer
1.4 barstow 815: *@param pw the graph file's PrintWriter
816: *@param dotFile the File handle for the graph file
1.1 barstow 817: *@param rdf the RDF text
818: *@param req a Servlet request
819: *@param graphFormat the graph's format
820: *@param saveRDF the RDF can be cached [saved to the file system]
821: *@param saveDOTFile the DOT file should be cached
822: */
1.22 duerst 823: private void generateGraph(PrintWriter out, PrintWriter pw,
1.4 barstow 824: File dotFile, String rdf, HttpServletRequest req, String graphFormat,
1.1 barstow 825: boolean saveRDF, boolean saveDOTFile)
826: {
827: try {
1.67 duerst 828: out.println("<hr title='visualisation' />");
1.66 duerst 829: out.println("<h3><a name='graph' id='graph'>" +
830: "Graph of the data model</a></h3>");
1.1 barstow 831:
832: // The temporary directory
833: String tmpDir = m_ServletTmpDir;
834:
835: // Add the graph footer
836: pw.println( " }");
837:
1.4 barstow 838: // Close the DOT input file so the GraphViz can
1.1 barstow 839: // open and read it
840: pw.close();
841:
842: // Generate a unique file name for the output file
843: // that will be created
844: String suffix = getFormatName(graphFormat, true);
845: File outputFile = createTempFile(tmpDir, TMP_FILE_PREFIX, suffix);
846: if (outputFile == null) {
847: out.println("Failed to create a temporary file for the graph. A graph cannot be generated.");
848: dotFile.delete();
849: return;
850: }
851:
852: // Pass the DOT data file to the GraphViz dot program
853: // so it can create a graph image of the data model
854: String dotFileName = dotFile.getAbsolutePath();
855: String outputFileName = outputFile.getAbsolutePath();
856:
1.8 barstow 857: if (!generateGraphFile(dotFileName, outputFileName, graphFormat)) {
1.1 barstow 858: out.println("An attempt to create a graph failed.");
859: dotFile.delete();
860: outputFile.delete();
861: return;
862: }
863: // Handle the DOT file
864: if (saveDOTFile) {
865: // Make the DOT file link'able if so requested
866: String dotPath = SERVLET_NAME + SUFFIX_TMP_DIR +
867: File.separator + dotFile.getName();
868: out.println("<a href=\"" + dotPath + "\">Download the DOT file.</a><br /><br />");
869: }
870: else {
871: // Delete it ...
872: dotFile.delete();
873: }
874:
875: // NOTE: Cannot delete the output file here because its
876: // pathname is returned to the client
877: String imagePath = SERVLET_NAME + SUFFIX_TMP_DIR + File.separator +
878: outputFile.getName();
879:
880: // Handle the embedded image formats first
881: if (graphFormat.equals(FORMAT_GIF_EMBED) ||
882: graphFormat.equals(FORMAT_PNG_EMBED)) {
883: if (outputFile.length() > 0)
1.67 duerst 884: out.println("<img alt='graph representation of RDF data' " +
885: "src='" + imagePath + "'/>");
1.1 barstow 886: else
887: out.println("The graph image file is empty.");
1.71 epietrig 888: }
889: else if (graphFormat.equals(FORMAT_SVG_EMBED)){
890: if (outputFile.length() > 0){
1.73 epietrig 891: out.println("<object type=\"image/svg+xml\" name=\"rdfsvg\" data=\"http://www.w3.org/RDF/Validator/"+imagePath+"\" width=\"640\" height=\"480\">Your browser does not support the <object> tag. The SVG representation of the model cannot be embedded in this page. You can use <b>SVG - link</b> or update your browser to a version supporting the <object> tag.</object>");
1.71 epietrig 892: }
893: else
894: out.println("The graph image file is empty.");
895: }
896: else if (graphFormat.equals(FORMAT_ISV_ZVTM)){
897: if (outputFile.length() > 0){
1.75 epietrig 898: out.println("<applet code=\"org.w3c.IsaViz.applet.IsvBrowser.class\"");
899: out.println("archive=\"lib/zvtm.jar,lib/isvapp.jar,lib/xercesImpl.jar,lib/xmlParserAPIs.jar\"");
900: out.println("width=\"640\" height=\"480\">");
901: out.println("<param name=\"type\" value=\"application/x-java-applet;version=1.4\" />");
902: out.println("<param name=\"scriptable\" value=\"false\" />");
903: out.println("<param name=\"width\" value=\"640\" />");
904: out.println("<param name=\"height\" value=\"480\" />");
905: out.println("<param name=\"svgFile\" value=\"http://www.w3.org/RDF/Validator/"+imagePath+"\" />");
1.71 epietrig 906: out.println("</applet>");
907: }
908: else
909: out.println("The graph image file is empty.");
910: }
911: else {
1.1 barstow 912: if (outputFile.length() > 0)
913: out.println("<a href=\"" + imagePath + "\">Get/view the graph's image file (" + suffix + ").</a><br /><br />");
914: else
915: out.println("The graph image file is empty.");
916: }
917:
918: // One last thing to do before exiting - copy the RDF to a file
919: if (saveRDF)
920: copyRDFStringToFile(tmpDir, rdf);
921:
922: } catch (Exception e) {
923: System.err.println("Exception generating graph: " + e.getMessage());
924: }
925: }
926:
927: /*
928: * Search the given string for substring "key"
929: * and if it is found, replace it with string "replacement"
930: *
931: *@param input the input string
932: *@param key the string to search for
933: *@param replacement the string to replace all occurences of "key"
1.3 barstow 934: *@return if no substitutions are done, input is returned; otherwise
1.1 barstow 935: * a new string is returned.
936: */
937: public static String replaceString(String input, String key,
938: String replacement)
939: {
1.3 barstow 940: try {
941: RE re = new RE(key);
942: return re.subst(input, replacement);
1.53 duerst 943: } catch (RESyntaxException e) {
1.3 barstow 944: return input;
1.1 barstow 945: }
946: }
947:
948: /*
949: * Print the document's header info
950: *
1.64 duerst 951: *@param out the servlet's output Writer
1.1 barstow 952: */
1.22 duerst 953: private void printDocumentHeader (PrintWriter out)
1.1 barstow 954: {
955: try {
956:
1.66 duerst 957: out.println( "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" +
1.6 barstow 958: " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" +
1.56 duerst 959: "<html><head>\n" +
1.66 duerst 960: "<title>RDF Validator Results</title>\n" +
1.56 duerst 961: "<link href='http://www.w3.org/StyleSheets/base.css' " +
962: "rel='stylesheet' type='text/css'/>\n" +
963: "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>\n" +
964: "<style type='text/css'>\n" +
1.67 duerst 965: " td {" +
1.6 barstow 966: " background:#EEEEEE;" +
967: " font-family:'courier new',courier,serif;" +
1.67 duerst 968: " border-style: solid;" +
969: " border-width: 1px;" +
970: " border-color: black;" +
971: " padding: 2px;" +
972: " }" +
973: " table {" +
974: " border-style: solid;" +
975: " border-width: 1px;" +
976: " border-color: black;" +
1.6 barstow 977: " }" +
1.56 duerst 978: "</style>\n" +
979: "</head>\n" +
1.66 duerst 980: "<body>\n" +
981: "<h1><a href='http://www.w3.org/'><img\n" +
982: "src='http://www.w3.org/Icons/WWW/w3c_home' alt='W3C' border='0'\n" +
983: " height='48' width='72' /></a>\n" +
984: "RDF Validation Results\n" +
1.71 epietrig 985: // "<p>classpath="+System.getProperty("java.class.path")+"</p>"+
1.66 duerst 986: "<a href='http://www.w3.org/RDF/'\n" +
987: " title='RDF Resource Description Framework'><img border='0'\n" +
988: " src='http://www.w3.org/RDF/icons/rdf_powered_button.48'\n" +
989: " alt='RDF Resource Description Framework Powered Icon' /></a></h1>\n" +
990: "<p><a href='#source'>Source</a> | " +
991: "<a href='#triples'>Triples</a> | " +
992: "<a href='#messages'>Messages</a> | " +
993: "<a href='#graph'>Graph</a> | " +
1.69 epietrig 994: "<a href='#feedback'>Feedback</a> | " +
995: "<a href='http://www.w3.org/RDF/Validator/'>Back to Validator Input</a></p>");
1.1 barstow 996:
997: } catch (Exception e) {
1.8 barstow 998: System.err.println("Exception (printDocumentHeader): " + e.getMessage());
1.1 barstow 999: }
1000: }
1001:
1002: /*
1003: * Print the rdf listing
1004: *
1.64 duerst 1005: *@param out the servlet's output Writer
1.1 barstow 1006: *@param rdf the RDF code
1.14 barstow 1007: *@param needCR if true, add a CarriageReturn to the output; if false,
1008: * do not add it
1.1 barstow 1009: */
1.22 duerst 1010: private void printListing (PrintWriter out, String rdf,
1.1 barstow 1011: boolean needCR)
1012: {
1013: try {
1.67 duerst 1014: out.println("<hr title='original source' />" +
1.66 duerst 1015: "<h3><a name='source' id='source'>" +
1016: "The original RDF/XML document</a></h3>" +
1.8 barstow 1017: "<pre>");
1.1 barstow 1018:
1.57 duerst 1019: String s = replaceString(rdf, "&", "&");
1.59 duerst 1020: s = replaceString(s, "<", "<");
1.1 barstow 1021:
1022: // Now output the RDF one line at a time with line numbers
1023: int lineNum = 1;
1024: int nl = 0;
1025: String terminator = needCR?"\n":"";
1026: do {
1027: String tok;
1028: nl = s.indexOf('\n');
1029: if ( nl == -1 ) {
1030: tok = s;
1031: } else {
1032: tok = s.substring(0,nl);
1033: s = s.substring(nl+1);
1034: }
1.8 barstow 1035: out.print("<a name=\"" + lineNum + "\">" + lineNum +
1036: "</a>: " + tok + terminator);
1.1 barstow 1037: lineNum++;
1038: } while ( nl != -1 );
1039:
1040: out.println("</pre>");
1041: } catch (Exception e) {
1.8 barstow 1042: System.err.println("Exception (printListing): " + e.getMessage());
1.1 barstow 1043: }
1044: }
1045:
1046: /*
1047: * Print the header for the triple listing
1048: *
1.64 duerst 1049: *@param out the servlet's output Writer
1.14 barstow 1050: *@param nTriples if true, output is N-Triples syntax
1.1 barstow 1051: */
1.22 duerst 1052: private void printTripleTableHeader (PrintWriter out, boolean nTriples)
1.1 barstow 1053: {
1054: try {
1055: if (nTriples) {
1.66 duerst 1056: out.println("<h3><a name='triples' id='triples'>" +
1057: "Triples of the Data Model in " +
1.6 barstow 1058: "<a href=\"http://www.w3.org/2001/sw/RDFCore/ntriples/\">" +
1.66 duerst 1059: "N-Triples</a> Format (Sub, Pred, Obj)</a></h3>" +
1.6 barstow 1060: "<pre>");
1.1 barstow 1061: } else {
1.67 duerst 1062: out.println("<hr title='triples' />");
1.66 duerst 1063: out.println("<h3><a name='triples' id='triples'>" +
1064: "Triples of the Data Model</a></h3>");
1.67 duerst 1065: out.println("<table frame='border' rules='all'><tr>" +
1.1 barstow 1066: "<td><b>Number</b></td>" +
1067: "<td><b>Subject</b></td>" +
1068: "<td><b>Predicate</b></td>" +
1069: "<td><b>Object</b></td>" +
1070: "</tr>");
1071: }
1072: } catch (Exception e) {
1.8 barstow 1073: System.err.println("Exception (printTripleTableHeader): " + e.getMessage());
1.1 barstow 1074: }
1075: }
1076:
1077: /*
1078: * Print the footer info for the triple listing
1079: *
1.64 duerst 1080: *@param out the servlet's output Writer
1.14 barstow 1081: *@param nTriples if true, output is N-Triples syntax
1.1 barstow 1082: */
1.22 duerst 1083: private void printTripleTableFooter (PrintWriter out,
1.1 barstow 1084: boolean nTriples)
1085: {
1086: try {
1087: if (nTriples)
1088: out.println("</pre>");
1089: else
1090: out.println("</table>");
1091: } catch (Exception e) {
1.8 barstow 1092: System.err.println("Exception (printTripleTableFooter): " + e.getMessage());
1.1 barstow 1093: }
1094: }
1095:
1096: /*
1097: * Print the document's footer info
1098: *
1.64 duerst 1099: *@param out the servlet's output Writer
1.1 barstow 1100: *@param rdf the RDF code
1101: */
1.22 duerst 1102: private void printDocumentFooter (PrintWriter out, String rdf)
1.1 barstow 1103: {
1104: try {
1105:
1.8 barstow 1106: String s;
1107:
1.67 duerst 1108: s = "<hr title='Problem reporting' />" +
1.66 duerst 1109: "<h3><a name='feedback' id='feedback'>Feedback</a></h3>" +
1.8 barstow 1110: "<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>" +
1111: "<form enctype='text/plain' method='post' action='mailto:" + MAIL_TO + "'>" +
1.9 barstow 1112: "<textarea cols='60' rows='4' name='report'></textarea>";
1.8 barstow 1113: out.println(s);
1.1 barstow 1114:
1.70 epietrig 1115: out.println("<input type='hidden' name='RDF' value=\"<?xml version="1.0">");
1.9 barstow 1116:
1.1 barstow 1117: // The listing is being passed as a parameter so the '<'
1118: // and '"' characters must be replaced with < and ",
1119: // respectively
1120: if (rdf != null) {
1.9 barstow 1121: String s1;
1.61 duerst 1122: s1 = replaceString(rdf, "&", "&");
1123: s1 = replaceString(s1, "<", "<");
1.11 barstow 1124: s1 = replaceString(s1, ">", ">");
1.9 barstow 1125: s1 = replaceString(s1, "\"", """);
1126: out.println(s1);
1.1 barstow 1127: }
1.61 duerst 1128: out.println("\" />");
1.1 barstow 1129:
1.61 duerst 1130: out.println("<input type='submit' value='Submit problem report' />" +
1.75 epietrig 1131: "</form>");
1.1 barstow 1132:
1.69 epietrig 1133: s= "<p><a href='#source'>Source</a> | " +
1134: "<a href='#triples'>Triples</a> | " +
1135: "<a href='#messages'>Messages</a> | " +
1136: "<a href='#graph'>Graph</a> | " +
1137: "<a href='#feedback'>Feedback</a> | " +
1138: "<a href='http://www.w3.org/RDF/Validator/'>Back to Validator Input</a></p>";
1139:
1140: out.println(s);
1.75 epietrig 1141: out.println("</body></html>");
1.69 epietrig 1142:
1.1 barstow 1143: } catch (Exception e) {
1.8 barstow 1144: System.err.println("Exception (printDocumentFooter): " + e.getMessage());
1.1 barstow 1145: }
1146: }
1147:
1148: /*
1.71 epietrig 1149: * Create a formatted string from the exception's message
1150: *
1151: *@param e any exception other than a SAXParseException
1152: *@return a formatted string
1153: */
1154: private static String formatOtherThanSAXParseEx(Exception e)
1155: {
1156: String msg = e.getMessage();
1157: if (msg == null)
1158: msg = e.toString();
1159: msg = replaceString(msg,"&","&");
1160: msg = replaceString(msg,"<","<");
1161: msg = replaceString(msg,">",">");
1162: msg = replaceString(msg,"\"",""");
1163: msg = replaceString(msg,"'","'");
1164: return msg;
1165: }
1166:
1167: /*
1.1 barstow 1168: * Servlet's get info method
1169: */
1170: public String getServletInfo () {
1171: return "Servlet wrapper for the ARP RDF parser. This is revision " + REVISION;
1172: }
1173:
1174: /*
1175: * Servlet's init method
1176: *
1177: *@param config the servlet's configuration object
1178: *@throws ServletException
1179: */
1180: public void init(ServletConfig config) throws ServletException
1181: {
1182: super.init (config);
1183:
1184: // Cache the parameters
1185: m_ServletTmpDir = config.getInitParameter(SERVLET_TMP_DIR);
1186:
1.68 duerst 1187: // Graph Viz paths extend from GRAPH_VIZ_ROOT unless absolute
1.1 barstow 1188: String GraphVizRoot = config.getInitParameter(GRAPH_VIZ_ROOT);
1189:
1.68 duerst 1190: m_GraphVizPath = config.getInitParameter(GRAPH_VIZ_PATH);
1191: m_GraphVizPath = (m_GraphVizPath.startsWith("/") ? "" : (GraphVizRoot + "/")) + m_GraphVizPath;
1192: m_GraphVizFontDir = config.getInitParameter(GRAPH_VIZ_FONT_DIR);
1193: m_GraphVizFontDir = (m_GraphVizFontDir.startsWith("/") ? "" : (GraphVizRoot + "/")) + m_GraphVizFontDir;
1.1 barstow 1194:
1.68 duerst 1195: if (m_ServletTmpDir == null || (GraphVizRoot == null &&
1196: (!m_GraphVizPath.startsWith("/") || !m_GraphVizFontDir.startsWith("/")))) {
1.1 barstow 1197: System.err.println (
1198: "<html>" +
1199: "<h1>Servlet Initialization Error</h1>" +
1200: "<h2>One or more of the following parameters has not been initialized: " +
1201: SERVLET_TMP_DIR + "," + GRAPH_VIZ_ROOT + "," +
1.16 barstow 1202: GRAPH_VIZ_FONT_DIR + "," + GRAPH_VIZ_PATH + "." +
1.1 barstow 1203: "</h2>" +
1204: "</html>");
1205: }
1206: }
1207:
1208: /*
1209: * Servlet's destroy info method
1210: */
1211: public void destroy () {
1212: super.destroy ();
1213: }
1214:
1215: /*
1.60 duerst 1216: * Servlet's doGet info method - supported for testing
1.1 barstow 1217: *
1218: *@param req the request
1219: *@param res the response
1220: *@throws ServletException, IOException
1221: */
1222: public void doGet (HttpServletRequest req, HttpServletResponse res)
1223: throws ServletException, IOException
1224: {
1225: String sRDF = req.getParameter(TEXT);
1226: String sURI = req.getParameter(URI);
1227:
1.60 duerst 1228: sRDF = (sRDF == null) ? "" : sRDF;
1229: sURI = (sURI == null) ? "" : sURI;
1.1 barstow 1230:
1.20 duerst 1231: try {
1.60 duerst 1232: sRDF = java.net.URLDecoder.decode(sRDF);
1233: sURI = java.net.URLDecoder.decode(sURI);
1.20 duerst 1234: } catch (Exception e) {
1235: System.err.println("Exception: URLDecoder.decode()");
1236: }
1.60 duerst 1237:
1238: process(req, res, sRDF, sURI);
1.1 barstow 1239: }
1240:
1241: /*
1242: * Servlet's doPost method
1243: *
1244: *@param req the request
1245: *@param res the response
1.17 duerst 1246: *@throws ServletException, IOException, java.io.UnsupportedEncodingException
1.1 barstow 1247: */
1248: public void doPost (HttpServletRequest req, HttpServletResponse res)
1249: throws ServletException, IOException
1250: {
1.19 duerst 1251: // String encoding = req.getCharacterEncoding();
1252: // if (encoding == null) {
1253: // req.setCharacterEncoding("UTF-8");
1254: // }
1.60 duerst 1255: String sRDF = req.getParameter(TEXT);
1256: String sURI = req.getParameter(URI);
1.1 barstow 1257:
1.60 duerst 1258: sRDF = (sRDF == null) ? "" : sRDF;
1259: sURI = (sURI == null) ? "" : sURI;
1.1 barstow 1260:
1261: process(req,res,sRDF, sURI);
1262: }
1263:
1264: /*
1265: * Output a Resource in NTriples syntax
1266: *
1.64 duerst 1267: *@param out the servlet's output Writer
1.1 barstow 1268: *@param r the Resource to output
1269: */
1.22 duerst 1270: static private void printResource(PrintWriter out, AResource r)
1.1 barstow 1271: {
1.26 duerst 1272: if (r.isAnonymous() )
1273: out.print("_:j" + r.getAnonymousID() + " ");
1274: else
1275: out.print("<" + r.getURI() + "> ");
1.1 barstow 1276: }
1277:
1278: /*
1.18 duerst 1279: * Convert to Hex and padd left with zeroes
1280: *
1281: *@param in the integer to convert and padd
1282: *@param in the length of the result
1283: *@return the padded string
1284: */
1285: // MJD: is there an easier way to do this?
1.20 duerst 1286: static private String hexPadd (int number, int length)
1.18 duerst 1287: {
1288: String t = Integer.toHexString(number).toUpperCase();
1.20 duerst 1289: int hexlength = t.length();
1.18 duerst 1290:
1291: if ( hexlength > length ) { // too long, truncate
1292: hexlength = length;
1293: }
1294:
1.20 duerst 1295: int zerolength = length - hexlength;
1.18 duerst 1296: String r = "";
1297:
1298: for (int i=0; i < zerolength; i++) {
1299: r += "0";
1300: }
1301: for (int i=0; i < hexlength; i++) {
1.24 duerst 1302: r += t.charAt(i);
1.18 duerst 1303: }
1304: return r;
1305: }
1306:
1307: /*
1.1 barstow 1308: * Output a Literal in NTriples syntax
1309: *
1.64 duerst 1310: *@param out the servlet's output Writer
1.1 barstow 1311: *@param l the Literal to output
1312: */
1.22 duerst 1313: static private void printNTripleLiteral(PrintWriter out, ALiteral l)
1.1 barstow 1314: {
1.28 duerst 1315: out.print("\"");
1316: char ar[] = l.toString().toCharArray();
1.1 barstow 1317:
1.28 duerst 1318: for (int i=0;i<ar.length;i++) {
1319: switch (ar[i]) {
1320: case '\\':
1321: out.print("\\\\");
1322: break;
1323: case '"':
1324: out.print("\\\"");
1325: break;
1326: case '\n':
1327: out.print("\\n");
1328: break;
1329: case '\r':
1330: out.print("\\r");
1331: break;
1332: case '\t':
1333: out.print("\\t");
1334: break;
1335: default:
1336: if ( ar[i] >= 32 && ar[i] <= 127 )
1337: out.print(ar[i]);
1338: else if ( ar[i] < 0xD800 || ar[i] >= 0xE000)
1339: out.print("\\u" + hexPadd(ar[i], 4) );
1340: else { // deal with surrogates
1341: // check for correct surrogate pair
1342: // this code should probably move somewhere else:
1343: // check when we get the input
1344: if ( ar[i] >= 0xDC00 ) {
1345: out.print("{{{error: lone low surrogate}}}");
1.18 duerst 1346: }
1.28 duerst 1347: else if ( ++i >= ar.length ) {
1348: out.print("{{{error: lone surrogate at end of string}}}");
1349: }
1350: else if ( ar[i] < 0xDC00 || ar[i] >= 0xE000 ) {
1351: out.print("{{{error: high surrogate not followed by low surrogate}}}");
1352: }
1353: // no errors, actually print
1354: else {
1355: int scalarvalue = 0x10000 + (ar[i-1] * 1024) + ar[i];
1356: out.print("\\U" + hexPadd(scalarvalue, 8) );
1357: }
1358: }
1.1 barstow 1359: }
1.28 duerst 1360: }
1361: out.print("\" ");
1.1 barstow 1362: }
1363:
1364: /*
1365: * Control point for outputing an triple in NTriple syntax
1366: *
1.64 duerst 1367: *@param out the servlet's output Writer
1.1 barstow 1368: *@param subj the subject
1369: *@param pred the predicate
1370: *@param objRes the object as a Resource (may be null)
1371: *@param objLit the object as a Literal (may be null)
1372: */
1.22 duerst 1373: static private void printNTriple(PrintWriter out, AResource subj,
1.1 barstow 1374: AResource pred, AResource objRes, ALiteral objLit)
1375: {
1.27 duerst 1376: printResource(out, subj);
1377: printResource(out, pred);
1378: if (objRes != null)
1379: printResource(out, objRes);
1380: else
1381: printNTripleLiteral(out, objLit);
1382: out.println(".");
1.1 barstow 1383: }
1384:
1385: /*
1386: * Create a HTML anchor from the URI or anonNode of the
1387: * given Resource
1388: *
1.14 barstow 1389: *@param r the Resource
1.1 barstow 1390: *@return the string as an HTML anchor
1391: */
1392: static private String addAnchor(AResource r)
1393: {
1394: if (r.isAnonymous())
1.14 barstow 1395: return ANON_NODE + r.getAnonymousID();
1.1 barstow 1396: else
1397: return "<a href='" + r.getURI() + "'>" + r.getURI() + "</a>";
1398: }
1399:
1400: /*
1401: * Output a triple as a row in HTML
1402: *
1.64 duerst 1403: *@param out the servlet's output Writer
1.1 barstow 1404: *@param subj the subject
1405: *@param pred the predicate
1406: *@param objRes the object as a Resource (may be null)
1407: *@param objLit the object as a Literal (may be null)
1408: *@param num the statement number
1409: */
1.22 duerst 1410: static private void printTableRow(PrintWriter out, AResource subj,
1.1 barstow 1411: AResource pred, AResource objRes, ALiteral objLit, int num)
1412: {
1.27 duerst 1413: out.println("<tr><td>" + num + "</td>");
1414: out.println("<td>" + addAnchor(subj) + "</td>");
1415: out.println("<td>" + addAnchor(pred) + "</td>");
1416: if (objRes != null)
1417: out.println("<td>" + addAnchor(objRes) + "</td>");
1418: else {
1419: out.println("<td>");
1420: String s1 = objLit.toString().trim();
1421: s1 = replaceString(s1, "<", "<");
1422: s1 = replaceString(s1, ">", ">");
1.74 epietrig 1423: s1 = replaceString(s1, "&", "&");
1424: s1 = """+s1+""";
1425: if (objLit.getLang()!=null && objLit.getLang().length()>0){//add language info if it exists
1426: s1+="@"+objLit.getLang();
1427: }
1428: if (objLit.getDatatypeURI()!=null){//add datatype info if it exists
1429: String s3=objLit.getDatatypeURI();
1430: s3 = replaceString(s3, "<", "<");
1431: s3 = replaceString(s3, ">", ">");
1432: s3 = replaceString(s3, "&", "&");
1433: if (s3.length()>0){
1434: s1+="^^"+s3;
1435: }
1436: }
1.27 duerst 1437: out.println(s1);
1438: out.println("</td>");
1439: }
1440: out.println("</tr>");
1.1 barstow 1441: }
1442:
1.4 barstow 1443: private static class SH implements StatementHandler
1.1 barstow 1444: {
1.22 duerst 1445: PrintWriter out;
1.12 barstow 1446: PrintWriter pw;
1.1 barstow 1447: boolean isNTriples;
1.12 barstow 1448: boolean printTriples;
1449: boolean printGraph;
1450: boolean anonNodesEmpty;
1.14 barstow 1451: int numStatements;
1452: int numLiterals;
1453: Hashtable subjects;
1454: int numSubjects;
1.71 epietrig 1455: String gFormat;
1.1 barstow 1456:
1457: /*
1.4 barstow 1458: * Constructuor for the StatementHandler. The primary
1459: * responsiblitly is to cache init variables
1.1 barstow 1460: *
1.64 duerst 1461: *@param out the servlet's output Writer
1.4 barstow 1462: *@param pw the Dot file's PrintWriter
1.1 barstow 1463: * syntax; otherwise use HTML syntax
1.12 barstow 1464: *@param isNTriples if true, output using the NTriples
1465: *@param printTriples if true, print the triples
1466: *@param printGraph if true, create the graph file
1467: *@param printGraph if true, anonomyous nodes should be empty
1.1 barstow 1468: */
1.22 duerst 1469: public SH(PrintWriter out, PrintWriter pw, boolean isNTriples,
1.71 epietrig 1470: boolean printTriples, boolean printGraph, boolean anonNodesEmpty,String graphFormat)
1.1 barstow 1471: {
1472: this.out = out;
1.12 barstow 1473: this.pw = pw;
1.1 barstow 1474: this.isNTriples = isNTriples;
1.12 barstow 1475: this.printTriples = printTriples;
1476: this.printGraph = printGraph;
1477: this.anonNodesEmpty = anonNodesEmpty;
1.14 barstow 1478:
1479: this.numStatements = 0;
1480: this.numLiterals = 0;
1481:
1482: this.subjects = new Hashtable();
1483: this.numSubjects = 0;
1.71 epietrig 1484: this.gFormat=graphFormat;
1.4 barstow 1485: }
1486:
1487: /*
1488: * Generic handler for a Resource/Resource/Resource triple (S/P/O).
1489: * Dispatches to the methods that do the real work.
1490: *
1491: *@param subj the subject
1492: *@param pred the predicate
1493: *@param obj the object (as a Resource)
1494: */
1495: public void statement(AResource subj, AResource pred, AResource obj)
1496: {
1.72 epietrig 1497: if (!ARPServlet.AT_LEAST_ONE_TRIPLE){ARPServlet.AT_LEAST_ONE_TRIPLE=true;}
1.12 barstow 1498: if (printTriples)
1499: statementResource(subj, pred, obj);
1500: if (printGraph)
1501: statementDotResource(subj, pred, obj);
1.4 barstow 1502: }
1503:
1504: /*
1505: * Generic handler for a Resource/Resource/Resource triple (S/P/O).
1506: * Dispatches to the methods that do the real work.
1507: *
1508: *@param subj the subject
1509: *@param pred the predicate
1510: *@param obj the object (as a Literal)
1511: */
1512: public void statement(AResource subj, AResource pred, ALiteral lit)
1513: {
1.72 epietrig 1514: if (!ARPServlet.AT_LEAST_ONE_TRIPLE){ARPServlet.AT_LEAST_ONE_TRIPLE=true;}
1.13 barstow 1515: numLiterals++;
1.12 barstow 1516: if (printTriples)
1517: statementLiteral(subj, pred, lit);
1518: if (printGraph)
1519: statementDotLiteral(subj, pred, lit);
1.1 barstow 1520: }
1521:
1522: /*
1523: * Handler for a Resource/Resource/Resource triple (S/P/O)
1524: * Outputs the given triple using NTriples or HTML syntax.
1525: *
1526: *@param subj the subject
1527: *@param pred the predicate
1528: *@param obj the object (as a Resource)
1529: */
1.4 barstow 1530: public void statementResource(AResource subj, AResource pred, AResource obj)
1.1 barstow 1531: {
1532: numStatements++;
1533:
1534: if (this.isNTriples)
1535: printNTriple(out, subj, pred, obj, null);
1536: else
1537: printTableRow(out, subj, pred, obj, null, this.numStatements);
1538: }
1.4 barstow 1539:
1.1 barstow 1540: /*
1541: * Handler for a Resource/Resource/Literal triple (S/P/O)
1542: * Outputs the given triple using NTriples or HTML syntax.
1543: *
1544: *@param subj the subject
1545: *@param pred the predicate
1546: *@param obj the object (as a Literal)
1547: */
1.4 barstow 1548: public void statementLiteral(AResource subj, AResource pred, ALiteral lit)
1.1 barstow 1549: {
1550: numStatements++;
1551:
1552: if (this.isNTriples)
1553: printNTriple(out, subj, pred, null, lit);
1554: else
1555: printTableRow(out, subj, pred, null, lit, this.numStatements);
1556: }
1.4 barstow 1557:
1.12 barstow 1558: /*
1559: * Print the first part of a triple's Dot file. See below for
1560: * more info. This is the same regardless if the triple's
1561: * object is a Resource or a Literal
1562: *
1563: *@param subj the subject
1564: */
1565: public void printFirstPart(AResource subj)
1566: {
1.14 barstow 1567: if (subj.isAnonymous()) {
1.12 barstow 1568: if (this.anonNodesEmpty) {
1.14 barstow 1569: Integer n = (Integer) subjects.get(subj.getAnonymousID());
1570: if (n == null) {
1571: this.numSubjects++;
1572: subjects.put(subj.getAnonymousID(), new Integer(this.numSubjects));
1.71 epietrig 1573: this.pw.println("\"" + ANON_NODE + subj.getAnonymousID() + "\" [label=\" \"];");
1.14 barstow 1574: }
1.12 barstow 1575: }
1.14 barstow 1576: this.pw.print("\"" + ANON_NODE + subj.getAnonymousID());
1.12 barstow 1577: } else {
1.71 epietrig 1578: if (gFormat!=null && gFormat.equals(FORMAT_ISV_ZVTM)){
1579: this.pw.println("\"" + subj.getURI() + "\" [fontcolor=\""+Float.toString(ARPServlet.resTBh)+","+Float.toString(ARPServlet.resTBs)+","+Float.toString(ARPServlet.resTBv)+"\",URL=\"" +subj.getURI() + "\"];");
1580: }
1581: else {
1582: this.pw.println("\"" + subj.getURI() + "\" [URL=\"" +subj.getURI() + "\"];");
1583: }
1.12 barstow 1584: this.pw.print("\"" + subj.getURI());
1585: }
1586: }
1587:
1.4 barstow 1588: /*
1589: * Handler for a Resource/Resource/Resource triple (S/P/O).
1590: * Outputs the given triple using Dot syntax.
1.12 barstow 1591: *
1592: * Each triple will be output in three lines of DOT code as
1593: * follows (not including the complication of anon nodes
1594: * and the possiblity that the anon nodes may be named
1595: * with an empty string):
1596: *
1597: * 1. "<subject>" [URL="<subject">];
1598: * 2. "<subject>" -> "<object>" [label="<predicate>",URL="<predicate>"];
1599: * 3. "<object>" [URL="<object>"];
1.4 barstow 1600: *
1601: *@param subj the subject
1602: *@param pred the predicate
1603: *@param obj the object (as a Resource)
1604: */
1605: public void statementDotResource(AResource subj, AResource pred, AResource obj)
1606: {
1607: if (this.pw == null) return;
1608:
1.12 barstow 1609: printFirstPart(subj);
1610:
1611: this.pw.print("\" -> ");
1.4 barstow 1612:
1.7 barstow 1613: if (obj.isAnonymous()) {
1.12 barstow 1614: if (this.anonNodesEmpty) {
1.71 epietrig 1615: if (gFormat!=null && gFormat.equals(FORMAT_ISV_ZVTM)){
1616: this.pw.println("\"" + ANON_NODE +obj.getAnonymousID() + "\" [fontcolor=\""+Float.toString(ARPServlet.prpTh)+","+Float.toString(ARPServlet.prpTs)+","+Float.toString(ARPServlet.prpTv)+"\",label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];");
1617: }
1618: else {
1619: this.pw.println("\"" + ANON_NODE +obj.getAnonymousID() + "\" [label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];");
1620: }
1.12 barstow 1621: } else {
1.71 epietrig 1622: if (gFormat!=null && gFormat.equals(FORMAT_ISV_ZVTM)){
1623: this.pw.println("\"" + ANON_NODE + obj.getAnonymousID() + "\" [fontcolor=\""+Float.toString(ARPServlet.prpTh)+","+Float.toString(ARPServlet.prpTs)+","+Float.toString(ARPServlet.prpTv)+"\",label=\"" + pred.getURI() + "\",URL=\"" +pred.getURI() + "\"];");
1624: }
1625: else {
1626: this.pw.println("\"" + ANON_NODE + obj.getAnonymousID() + "\" [label=\"" + pred.getURI() + "\",URL=\"" +pred.getURI() + "\"];");
1627: }
1.12 barstow 1628: }
1.7 barstow 1629: } else {
1.71 epietrig 1630: if (gFormat!=null && gFormat.equals(FORMAT_ISV_ZVTM)){
1631: this.pw.println("\"" + obj.getURI() + "\" [fontcolor=\""+Float.toString(ARPServlet.prpTh)+","+Float.toString(ARPServlet.prpTs)+","+Float.toString(ARPServlet.prpTv)+"\",label=\"" +pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];");
1632: this.pw.println("\"" + obj.getURI() + "\" [fontcolor=\""+Float.toString(resTBh)+","+Float.toString(resTBs)+","+Float.toString(resTBv)+"\",URL=\"" +obj.getURI() + "\"];");
1633: }
1634: else {
1635: this.pw.println("\"" + obj.getURI() + "\" [label=\"" +pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];");
1636: this.pw.println("\"" + obj.getURI() + "\" [URL=\"" +obj.getURI() + "\"];");
1637: }
1.14 barstow 1638: }
1.4 barstow 1639: }
1640:
1641: /*
1642: * Handler for a Resource/Resource/Literal triple (S/P/O).
1643: * Outputs the given triple using Dot syntax.
1.12 barstow 1644: *
1645: * Each triple will be output in three lines of DOT code as
1646: * follows (not including the complication of anon nodes
1647: * and the possiblity that the anon nodes may be named
1648: * with an empty string):
1649: *
1650: * 1. "<subject>" [URL="<subject">];
1651: * 2. "<subject>" -> "<literal>" [label="<predicate>",URL="<predicate>"];
1652: * 3. "<literal>" [shape="box"];
1.4 barstow 1653: *
1654: *@param subj the subject
1655: *@param pred the predicate
1656: *@param obj the object (as a Literal)
1657: */
1658: public void statementDotLiteral(AResource subj, AResource pred, ALiteral lit)
1659: {
1660: if (this.pw == null) return;
1661:
1.12 barstow 1662: printFirstPart(subj); // Same as Res/Res/Res
1.4 barstow 1663:
1664: /*
1665: * Before outputing the object (Literal) do the following:
1666: *
1667: * o GraphViz/DOT cannot handle embedded line terminators characters
1668: * so they must be replaced with spaces
1669: * o Limit the number of chars to make the graph legible
1670: * o Escape double quotes
1671: */
1672: String s1 = new String(lit.toString());
1673: s1 = s1.replace('\n', ' ');
1674: s1 = s1.replace('\f', ' ');
1675: s1 = s1.replace('\r', ' ');
1676: if (s1.indexOf('"') != -1)
1677: s1 = replaceString(s1, "\"", "\\\"");
1678:
1679: // Anything beyond 80 chars makes the graph too large
1680: String tmpObject;
1681: if (s1.length() >= 80)
1682: tmpObject = s1.substring(0, 80) + " ...";
1683: else
1684: tmpObject = s1.substring(0, s1.length());
1685:
1.13 barstow 1686: // Create a temporary label for the literal so that if
1687: // it is duplicated it will be unique in the graph and
1688: // thus have its own node.
1689: String tmpName = "Literal_" + Integer.toString(this.numLiterals);
1690: this.pw.print("\" -> \"" + tmpName);
1.4 barstow 1691:
1.71 epietrig 1692: if (gFormat!=null && gFormat.equals(FORMAT_ISV_ZVTM)){
1693: this.pw.println("\" [fontcolor=\""+Float.toString(ARPServlet.prpTh)+","+Float.toString(ARPServlet.prpTs)+","+Float.toString(ARPServlet.prpTv)+"\",label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];");
1694: this.pw.println("\"" + tmpName + "\" [fontcolor=\""+Float.toString(litTBh)+","+Float.toString(litTBs)+","+Float.toString(litTBv)+"\",shape=box,label=\"" + tmpObject + "\"];");
1695: }
1696: else {
1697: this.pw.println("\" [label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];");
1698: this.pw.println("\"" + tmpName + "\" [shape=box,label=\"" + tmpObject + "\"];");
1699: }
1.4 barstow 1700: }
1701: }
1702:
1.22 duerst 1703: private void printErrorMessages(PrintWriter out, SaxErrorHandler eh)
1.5 barstow 1704: {
1.66 duerst 1705: try {
1706: String s;
1707: boolean c = true;
1708:
1709: out.println("<h2><a name='messages' id='messages'>" +
1710: "Validation Results</a></h2>");
1711:
1712: s = eh.getFatalErrors();
1713: if (s != null && s.length() >= 1) {
1714: out.println("<h3>Fatal Error Messages</h3>" + s);
1715: c = false;
1716: }
1717:
1718: s = eh.getErrors();
1719: if (s != null && s.length() >= 1) {
1720: out.println("<h3>Error Messages</h3>" + s);
1721: c = false;
1722: }
1723:
1724: s = eh.getWarnings();
1725: if (s != null && s.length() >= 1) {
1726: out.println("<h3>Warning Messages</h3>" + s);
1727: c = false;
1728: }
1.5 barstow 1729:
1.72 epietrig 1730: if (c){
1731: if (AT_LEAST_ONE_TRIPLE){
1732: out.println("<p>Your RDF document validated successfully.</p>");
1733: }
1734: else {
1735: out.println("<p>Error: Your document does not contain any RDF statement.</p>");
1736: }
1737: AT_LEAST_ONE_TRIPLE=false;
1738: }
1.69 epietrig 1739:
1.72 epietrig 1740: /*the following should not happen anymore, as we use ARP2 which supports datatypes, but leave it there for now, just in case*/
1.69 epietrig 1741: s = eh.getDatatypeErrors();
1742: if (s != null && s.length() >= 2){//2 to prevent an arrayindexoutofbounds exception
1743: out.println("<h3>Note about datatypes</h3>");
1744: out.println("<p>Datatypes are used on lines "+s.substring(0,s.length()-2)+". This RDF feature is not yet supported by the RDF Validator. Literals are treated as untyped.</p>");
1745: }
1746:
1.5 barstow 1747: } catch (Exception e) {
1748: System.err.println(SERVLET_NAME + ": Error printing error messages.");
1749: }
1750: }
1751:
1752: /*
1753: * Initialize the graph output file. If an error occurs, this
1754: * function will print an error message.
1755: *
1.64 duerst 1756: *@param out the servlet's output Writer
1.5 barstow 1757: *@req the servlet request object
1758: *@return the File object for the graph file; null if an error occurs
1759: */
1.22 duerst 1760: private File initGraphFile(PrintWriter out,
1.4 barstow 1761: HttpServletRequest req)
1762: {
1763: try {
1764: // Stop if any of the parameters are missing
1765: if (m_ServletTmpDir == null ||
1766: m_GraphVizPath == null ||
1.16 barstow 1767: m_GraphVizFontDir == null)
1.4 barstow 1768: {
1769: // Put the paths in a comment in the returned content
1770: out.println("<!-- SERVLET_TMP_DIR = " + m_ServletTmpDir);
1771: out.println("GRAPH_VIZ_PATH = " + m_GraphVizPath);
1772: out.println("GRAPH_FONT_DIR = " + m_GraphVizFontDir + " -->");
1773:
1.12 barstow 1774: out.println("<h1>Servlet initialization failed</h1>");
1775: out.println("Please send a message to <a href='mailto:" + MAIL_TO + "'>" + MAIL_TO + "</a> and mention this problem.");
1.4 barstow 1776: return null;
1777: }
1778: } catch (Exception e) {
1779: System.err.println("Unable to create a temporary graph file. A graph cannot be generated.");
1780: return null;
1781: }
1782:
1783: File dotFile = null;
1784:
1.27 duerst 1785: // Must generate a unique file name that the DOT handler will use
1786: dotFile = createTempFile(m_ServletTmpDir, TMP_FILE_PREFIX, SUFFIX_DOT);
1787: if (dotFile == null) {
1788: out.println("<h1>Failed to create a temporary graph file. A graph cannot be generated.</h1>");
1789: return null;
1790: }
1.4 barstow 1791:
1792: return dotFile;
1.1 barstow 1793: }
1.6 barstow 1794:
1795: /*
1796: * Check if the given URI is supported or not
1797: *
1.64 duerst 1798: *@param out the servlet's output Writer
1.6 barstow 1799: *@param uri the URI to check
1800: *@return true if the URI is supported; false otherwise
1801: */
1.22 duerst 1802: private boolean isURISupported(PrintWriter out, String uri)
1.6 barstow 1803: {
1804: try {
1805: if (uri.length() >= 4 && uri.substring(0,4).equalsIgnoreCase("file")) {
1806: out.println("<h1>file URI Schemes are NOT Supported</h1>");
1807: out.println("URIs from the 'file' URI scheme are not supported by this servlet.");
1808: return false;
1809: }
1810: } catch (Exception e) {
1811: System.err.println("Exception in isURISupported.");
1812: return false;
1813: }
1814:
1815: return true;
1816: }
1.1 barstow 1817:
1818: /*
1819: * Handle the servlets doGet or doPut request
1820: *
1821: *@param req the servlet's request
1822: *@param res the servlet's response
1823: *@throws SevletException, IOException
1824: */
1825: private void process(HttpServletRequest req, HttpServletResponse res,
1.52 duerst 1826: String sRDF, String sURI) throws ServletException, IOException
1.1 barstow 1827: {
1.12 barstow 1828: String sSaveRDF = req.getParameter (SAVE_RDF);
1829: String sSaveDOTFile = req.getParameter (SAVE_DOT_FILE);
1830: String sNTriples = req.getParameter (NTRIPLES);
1831: String sEmbedded = req.getParameter (EMBEDDED_RDF);
1832: String sTriplesAndGraph = req.getParameter (TRIPLES_AND_GRAPH);
1833: String sAnonNodesEmpty = req.getParameter (ANON_NODES_EMPTY);
1.60 duerst 1834: String sParse = req.getParameter (PARSE);
1.63 duerst 1835: String sFormat = req.getParameter (FORMAT);
1836: if (sFormat==null)
1837: sFormat = DEFAULT_FORMAT;
1.12 barstow 1838:
1839: // Set the print flags
1840: boolean printTriples = true;
1841: boolean printGraph = true;
1842: if (sTriplesAndGraph != null) {
1843: if (sTriplesAndGraph.equals(PRINT_TRIPLES))
1844: printGraph = false;
1845: if (sTriplesAndGraph.equals(PRINT_GRAPH))
1846: printTriples = false;
1847: }
1.1 barstow 1848:
1.12 barstow 1849: // Determine if printing the triples and/or graph
1850: boolean anonNodesEmpty = (sAnonNodesEmpty != null) ? true : false;
1.1 barstow 1851: boolean nTriples = (sNTriples != null) ? true : false;
1.12 barstow 1852:
1.10 barstow 1853: // ARP parser has embedded = true by default so if user
1854: // wants embedding, must set it to false
1855: boolean embedded = (sEmbedded != null) ? false : true;
1.1 barstow 1856:
1.60 duerst 1857: res.setContentType ("text/html;charset=utf-8");
1858: PrintWriter out = res.getWriter ();
1859: printDocumentHeader (out);
1.65 duerst 1860:
1.60 duerst 1861: boolean parseRDF = true;
1862: if (sParse != null)
1863: parseRDF = sParse.equals("Parse RDF");
1.65 duerst 1864: else if (!sURI.equals("")) // continue even if PARSE is not present
1.60 duerst 1865: parseRDF = false;
1866:
1.65 duerst 1867: if (parseRDF) sURI = "";
1868: else sRDF = "";
1869:
1870: // getting encoding right: bad hack, but it works :-(
1.60 duerst 1871: sRDF = new String(sRDF.getBytes("iso-8859-1"), "utf-8");
1872: sURI = new String(sURI.getBytes("iso-8859-1"), "utf-8");
1873:
1874: if ((!parseRDF && sURI.equals("")) || (parseRDF && sRDF.equals(""))) {
1875: out.println("<h1>" + (parseRDF ? "RDF" : "URI")
1876: + " was not specified.</h1>");
1877: printDocumentFooter(out, null);
1878: return;
1879: }
1880:
1.1 barstow 1881: String xmlBase = DEFAULT_NAMESPACE;
1882:
1.60 duerst 1883: if (!sURI.equals("")) {
1.6 barstow 1884:
1885: // First check for unsupported URIs
1886: if (!isURISupported(out, sURI)) {
1887: printDocumentFooter(out, null);
1888: return;
1889: }
1890:
1.1 barstow 1891: xmlBase = sURI;
1.53 duerst 1892: try {
1893: sRDF = getRDFfromURI(sURI);
1894: if (sRDF == null)
1895: throw new getRDFException("The URI may not exist or the server is down.@@");
1896: } catch (getRDFException e) {
1897: out.println("<h1>RDF Load Error</h1>");
1898: out.println("An attempt to load the RDF from URI '" + sURI +
1899: "' failed. (" + e.getMessage() + ")");
1900: printDocumentFooter(out, null);
1901: return;
1902: }
1.1 barstow 1903: }
1.4 barstow 1904:
1905: PrintWriter pw = null; // The writer for the graph file
1.65 duerst 1906: OutputStreamWriter osw = null;
1.4 barstow 1907: File dotFile = null; // The graph file
1.63 duerst 1908: if (printGraph) {
1.4 barstow 1909: dotFile = initGraphFile(out, req);
1910: if (dotFile == null)
1911: // Assume error has been reported
1912: return;
1913: // Create a PrintWriter for the DOT handler
1.65 duerst 1914: FileOutputStream fos = new FileOutputStream(dotFile);
1915: if (fos != null)
1916: osw = new OutputStreamWriter(fos, "utf-8");
1917: if (osw != null)
1918: pw = new PrintWriter(osw);
1.4 barstow 1919: if (pw != null)
1920: // Add the graph header
1.69 epietrig 1921: processGraphParameters (req, pw, (sFormat.equals(FORMAT_PNG_EMBED)) || (sFormat.equals(FORMAT_PNG_LINK)) || (sFormat.equals(FORMAT_GIF_EMBED)) || (sFormat.equals(FORMAT_GIF_LINK)));
1.4 barstow 1922: }
1923:
1924: // Create the StatementHandler - it will handle triples for
1925: // the table/ntriples and the graph file
1.71 epietrig 1926: SH sh = new SH(out, pw, nTriples, printTriples, printGraph, anonNodesEmpty,sFormat);
1.4 barstow 1927:
1928: // Create the ErrorHandler
1929: SaxErrorHandler errorHandler = new SaxErrorHandler(out, false);
1930:
1931: // Create and initialize the parser
1.71 epietrig 1932:
1933: // System.err.println("-----------------------------------------------");
1934: // System.err.println("Determining class for ARP");
1935: // String arp="com.hp.hpl.jena.rdf.arp.ARP";
1936: // try {
1937: // Class c = Class.forName (arp);
1938: // String classRes = "/"+arp.replace ('.', '/')+
1939: // ".class";
1940: // System.out.println ("Class "+arp+
1941: // " URL: "+c.getResource (classRes));
1942: // }
1943: // catch (Throwable t)
1944: // {
1945: // System.out.println ("Unable to locate class "+arp);
1946: // }
1947:
1.4 barstow 1948: ARP parser = new com.hp.hpl.jena.rdf.arp.ARP();
1949: parser.setErrorHandler(errorHandler);
1950: parser.setStatementHandler(sh);
1.10 barstow 1951: parser.setEmbedding(embedded);
1.72 epietrig 1952: parser.setStrictErrorMode();
1.61 duerst 1953: printListing (out, sRDF, !parseRDF);
1.12 barstow 1954:
1955: if (printTriples)
1956: printTripleTableHeader (out, nTriples);
1.1 barstow 1957:
1958: try {
1.52 duerst 1959: StringReader sr = new StringReader (sRDF);
1.69 epietrig 1960: if (xmlBase!=null && xmlBase.length()>0){parser.load(sr, xmlBase);}
1961: else {parser.load(sr);}
1.1 barstow 1962: } catch (Exception ex) {
1.66 duerst 1963: out.println ("<h1><a name='messages' id='messages'>Parser " +
1964: "Loading Error</a></h1>");
1.71 epietrig 1965: out.println ("Exception parsing: " +formatOtherThanSAXParseEx(ex));
1.53 duerst 1966: printDocumentFooter(out, null);
1967: return;
1.1 barstow 1968: }
1969:
1.12 barstow 1970: if (printTriples)
1971: printTripleTableFooter(out, nTriples);
1.5 barstow 1972:
1973: printErrorMessages(out, errorHandler);
1.1 barstow 1974:
1.52 duerst 1975: res.flushBuffer();
1.12 barstow 1976: if (sFormat != null && printGraph) {
1.4 barstow 1977: generateGraph(out, pw, dotFile, sRDF, req, sFormat,
1.1 barstow 1978: (sSaveRDF != null) ? true : false,
1979: (sSaveDOTFile != null && sSaveDOTFile.equals ("on") ? true : false));
1980: }
1981:
1982:
1.61 duerst 1983: if (!parseRDF)
1.9 barstow 1984: printDocumentFooter(out, null);
1985: else
1986: printDocumentFooter(out, sRDF);
1.1 barstow 1987: }
1988: }
Webmaster