/*********************************************************************** * * ARPServlet - this servlet implements an RDF Validation service. As * of this writing, the following RDF validation service used this * servlet: * * http://www.w3.org/RDF/Validator/ * *********************************************************************** * * Copyright © World Wide Web Consortium, (Massachusetts Institute of * Technology, Institut National de Recherche en Informatique et en * Automatique, Keio University). * * All Rights Reserved. * * Please see the full Copyright clause at * * *********************************************************************** * * This servlet is a wrapper for the ARP RDF parser. See the following * for information about the ARP RDF parser: * * http://www.hpl.hp.co.uk/people/jjc/arp/ * *********************************************************************** * * Implementation notes: * * o This servlet supports the HTTP POST operation; it does not * support the HTTP GET operation * * o Depending upon the parameters given to the servlet it may * invoke a GraphViz suprocess to generate a graph of the RDF. * See the following for more information about GraphViz: * * http://www.research.att.com/sw/tools/graphviz/ * * The servlet assumes version 1.7.4 of GraphViz. * * o Depending upon the parameters given to the servlet, the RDF * to be validated may be copied to a file. The name of the file * is automatically generated via Java's temporary file APIs. The * location of the directory where the file is stored is configured * via the serverlet's init() method. See below for more information. * * o See the section on Server Initialization for more information. * *********************************************************************** * * HTTP POST parameters - the servlet expects/assumes the following * variables are defined via the HTTP POST request: * * RDF - the RDF (assumed to be in RDF/XML syntax) to be validated * * SAVE_DOT_FILE - if "on", the GraphViz DOT file is saved and a * link to the file is returned; otherwise the DOT file is not saved * * SAVE_RDF - if "on", the RDF will be copied to a file; otherwise * the RDF is not copied to a file * * EMBEDDED_RDF - if "on", then the RDF is not enclosed in ... * tags; otherwise it assumed that the RDF is enclosed in these tags. * * URI - the URI of the RDF to validate; this parameter may not be * specified; if this parameter and the RDF parameter are both * specified, this parameter takes precedence * * ORIENTATION - the graph's orientation (left to right or top to * bottom); default is left to right * * FONT_SIZE - the font size to use (10, 12, 14, 16 and 20 are * supported); the default is 10 * * ANON_NODES_EMPTY - if "on", anonymous nodes are not labeled; otherwise * anonymous nodes are labeled; * * TRIPLES_AND_GRAPH - support values are: * * PRINT_BOTH - display triples and a graph (the default) * PRINT_TRIPLES - only display the triples * PRINT_GRAPH - only display the graph * * GRAPH_FORMAT - the graph's output format. Supported values are: * * GIF_EMBED - embed the graph as a GIF (the default) * GIF_LINK - don't embed the GIF but create a link for it * SVG_LINK - create the graph in SVG format and create a link to the file * PNG_EMBED - create the graph in PNG format and embed the graph in the * document that is returned * PNG_LINK - create the graph in PNG format and create a link to the file * PS_LINK - create a PostScript image of the file and a link to the file * HP_PCL_LINK - create a HPGL/2 - PCL (Laserwriter) image of the file * and a link to the file * HP_GL_LINK - create a HPGL - PCL (pen plotter) image of the file and * a link to the file * * NTRIPLES if "on" the tabular output will be in the NTriples format; * otherwise a table of Subject, Predicate, Objects will be generated * *********************************************************************** * * Server Initialization - this servlet requires the following * parameters be set in the servlet's init() method - via the * ServletConfig object: * * GRAPH_VIZ_ROOT - the absolute path of the top-level directory containing * GraphViz's binary distribution * * GRAPH_VIZ_PATH - the relative path (based on GRAPH_VIZ_ROOT) of * the DOT executable (e.g. dotneato/dot) - the program used to generate * a graph from a DOT file. * * GRAPH_VIZ_FONT_DIR - the relative path (based on GRAPH_VIZ_ROOT) of * the fonts directory used by GraphViz (e.g. Fonts) * * SERVLET_TMP_DIR - the absolute path of the directory to be used to * store temporary files used by the servlet and GraphViz. This * directory must be writable by the servlet. * * NOTE - Some files created by the servlet are not removed by * servlet (e.g. graph image files). * * If any of these parameters are not defined, the servlet will NOT * validate the RDF. * *********************************************************************** * * Dependencies - this servlet requires the following Java packages * as well as GraphViz (described above): * * ARP RDF parser: http://www.hpl.hp.co.uk/people/jjc/arp/download.html * * SAX-based XML parser: e.g. Xerces at http://xml.apache.org/ * * Java servlet package: http://java.sun.com/products/servlet/archive.html * * Apache Regular Expression: http://jakarta.apache.org/builds/jakarta-regexp/release/v1.2/ * *********************************************************************** * * Author: Art Barstow * Author (internationalization): Martin J. Duerst * * $Id: ARPServlet.java,v 1.30 2002/08/06 01:24:17 duerst Exp $ * ***********************************************************************/ // http://dev.w3.org/cvsweb/java/classes/org/w3c/rdf/examples/ package org.w3c.rdf.examples; import java.io.*; import java.net.MalformedURLException; import java.net.URL; import java.util.StringTokenizer; import java.util.Enumeration; import java.util.Hashtable; // http://java.sun.com/products/servlet/2.2/javadoc/javax/servlet/package-summary.html import javax.servlet.*; import javax.servlet.http.*; // http://xml.apache.org/apiDocs/org/xml/sax/package-summary.html import org.xml.sax.InputSource; import org.xml.sax.Parser; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.ErrorHandler; import org.xml.sax.helpers.*; // http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html import org.apache.regexp.RE; // http://www.hpl.hp.co.uk/people/jjc/arp/apidocs/index.html import com.hp.hpl.jena.rdf.arp.*; public class ARPServlet extends HttpServlet { final static public String REVISION = "$Id: ARPServlet.java,v 1.30 2002/08/06 01:24:17 duerst Exp $"; // The email address for bug reports private static final String MAIL_TO = "www-rdf-validator@w3.org"; // Names of the POST parameters (described above) and their // defaults (if applicable) private static final String TEXT = "RDF"; private static final String SAVE_DOT_FILE = "SAVE_DOT_FILE"; private static final String SAVE_RDF = "SAVE_RDF"; private static final String EMBEDDED_RDF = "EMBEDDED_RDF"; private static final String URI = "URI"; private static final String NTRIPLES = "NTRIPLES"; private static final String ANON_NODES_EMPTY = "ANON_NODES_EMPTY"; private static final String NODE_COLOR = "NODE_COLOR"; private static final String DEFAULT_NODE_COLOR = "black"; private static final String NODE_TEXT_COLOR = "NODE_TEXT_COLOR"; private static final String DEFAULT_NODE_TEXT_COLOR = "black"; private static final String EDGE_COLOR = "EDGE_COLOR"; private static final String DEFAULT_EDGE_COLOR = "black"; private static final String EDGE_TEXT_COLOR = "EDGE_TEXT_COLOR"; private static final String DEFAULT_EDGE_TEXT_COLOR = "black"; private static final String ORIENTATION = "ORIENTATION"; private static final String DEFAULT_ORIENTATION = "TB"; // Top to Bottom private static final String FONT_SIZE = "FONT_SIZE"; private static final String DEFAULT_FONT_SIZE = "10"; // Print graph and/or triples private static final String TRIPLES_AND_GRAPH = "TRIPLES_AND_GRAPH"; private static final String PRINT_BOTH = "PRINT_BOTH"; private static final String PRINT_TRIPLES = "PRINT_TRIPLES"; private static final String PRINT_GRAPH = "PRINT_GRAPH"; // Graph formats private static final String FORMAT = "FORMAT"; private static final String FORMAT_GIF_EMBED = "GIF_EMBED"; private static final String FORMAT_GIF_LINK = "GIF_LINK"; private static final String FORMAT_SVG_LINK = "SVG_LINK"; private static final String FORMAT_PNG_EMBED = "PNG_EMBED"; private static final String FORMAT_PNG_LINK = "PNG_LINK"; private static final String FORMAT_PS_LINK = "PS_LINK"; private static final String FORMAT_HP_PCL_LINK = "HP_PCL_LINK"; private static final String FORMAT_HP_GL_LINK = "HP_GL_LINK"; // Fonts are not currently configurable private static final String DEFAULT_FONT = "arial"; // Names of the servlet's parameters - for Jigsaw web server private static final String SERVLET_TMP_DIR = "SERVLET_TMP_DIR"; private static final String GRAPH_VIZ_ROOT = "GRAPH_VIZ_ROOT"; private static final String GRAPH_VIZ_PATH = "GRAPH_VIZ_PATH"; private static final String GRAPH_VIZ_FONT_DIR = "GRAPH_VIZ_FONT_DIR"; // Variables for the servlet's parameters private static String m_ServletTmpDir = null; private static String m_GraphVizPath = null; private static String m_GraphVizFontDir = null; // Names of environment variable needed by GraphVis private static String DOTFONTPATH = "DOTFONTPATH"; private static String LD_LIBRARY_PATH = "LD_LIBRARY_PATH"; // Names used for temporary files private static final String TMP_FILE_PREFIX = "servlet_"; private static final String SUFFIX_TMP_DIR = ".tmp"; private static final String SUFFIX_DOT = ".dot"; private static final String SUFFIX_RDF = ".rdf"; // Names used for file suffixes and for GraphViz's command line // option private static final String NAME_GIF = "gif"; private static final String NAME_HPGL = "hpgl"; private static final String NAME_PCL = "pcl"; private static final String NAME_PNG = "png"; private static final String NAME_PS = "ps"; private static final String NAME_SVG = "svg"; // Default GraphViz parameter names and their default values // Servlet name private static final String SERVLET_NAME = "ARPServlet"; // Name for the DOT file title private static final String DOT_TITLE = "dotfile"; // The string to use to prefix anonymous nodes. private static final String ANON_NODE = "genid:"; // The string to use for a namespace name when no // namespace is available - e.g. for the RDF that is // directly entered into the input form. private static final String DEFAULT_NAMESPACE = "online:"; /* * Create a File object from the given directory and file names * *@param directory the file's directory *@param prefix the file's prefix name (not its directory) *@param suffix the file's suffix or extension name *@return a File object if a temporary file is created; null otherwise */ private File createTempFile (String directory, String prefix, String suffix) { File f; try { File d = new File(directory); f = File.createTempFile(prefix, suffix, d); } catch (Exception e) { return null; } return f; } /* * Given a URI string, open it, read its contents into a String * and return the String * *@param uri the URI to open *@return the content at the URI or null if any error occurs */ private String getByteStream (String uri) { try { URL url = new URL(uri); InputStream is = url.openStream(); String s = new String(""); int c; int numRead = 0; while ((c = is.read()) != -1) { s += (char)c; if (numRead == 15) { // A server could return content but not the RDF/XML that // we need. Check the beginning of s and if it looks like // a generic HTML message, return an error. if (s.startsWith(""; } /* * Handle a fatal parse error * *@param e the SAX Parse Exception */ public void fatalError(org.xml.sax.SAXParseException e) throws org.xml.sax.SAXException { if (this.silent) return; this.fatalErrors += "FatalError: " + format(e) + "
"; } /* * Handle a parse warning * *@param e the SAX Parse Exception */ public void warning(org.xml.sax.SAXParseException e) throws org.xml.sax.SAXException { if (this.silent) return; this.warnings += "Warning: " + format(e) + "
"; } /* * Return the error messages * *@return the error messages or an empty string if there are * no messages */ public String getErrors() { return this.errors; } /* * Return the fatal error messages * *@return the fatal error messages or an empty string if there are * no messages */ public String getFatalErrors() { return this.fatalErrors; } /* * Return the warning messages * *@return the warning messages or an empty string if there are * no messages */ public String getWarnings() { return this.warnings; } } /* * Generate a graph of the RDF data model * *@param out the servlet's output stream *@param pw the graph file's PrintWriter *@param dotFile the File handle for the graph file *@param rdf the RDF text *@param req a Servlet request *@param graphFormat the graph's format *@param saveRDF the RDF can be cached [saved to the file system] *@param saveDOTFile the DOT file should be cached */ private void generateGraph(PrintWriter out, PrintWriter pw, File dotFile, String rdf, HttpServletRequest req, String graphFormat, boolean saveRDF, boolean saveDOTFile) { try { out.println("
"); out.println("

Graph of the data model

"); // The temporary directory String tmpDir = m_ServletTmpDir; // Add the graph footer pw.println( " }"); // Close the DOT input file so the GraphViz can // open and read it pw.close(); // Generate a unique file name for the output file // that will be created String suffix = getFormatName(graphFormat, true); File outputFile = createTempFile(tmpDir, TMP_FILE_PREFIX, suffix); if (outputFile == null) { out.println("Failed to create a temporary file for the graph. A graph cannot be generated."); dotFile.delete(); return; } // Pass the DOT data file to the GraphViz dot program // so it can create a graph image of the data model String dotFileName = dotFile.getAbsolutePath(); String outputFileName = outputFile.getAbsolutePath(); if (!generateGraphFile(dotFileName, outputFileName, graphFormat)) { out.println("An attempt to create a graph failed."); dotFile.delete(); outputFile.delete(); return; } // Handle the DOT file if (saveDOTFile) { // Make the DOT file link'able if so requested String dotPath = SERVLET_NAME + SUFFIX_TMP_DIR + File.separator + dotFile.getName(); out.println("Download the DOT file.

"); } else { // Delete it ... dotFile.delete(); } // NOTE: Cannot delete the output file here because its // pathname is returned to the client String imagePath = SERVLET_NAME + SUFFIX_TMP_DIR + File.separator + outputFile.getName(); // Handle the embedded image formats first if (graphFormat.equals(FORMAT_GIF_EMBED) || graphFormat.equals(FORMAT_PNG_EMBED)) { if (outputFile.length() > 0) out.println(""); else out.println("The graph image file is empty."); } else { if (outputFile.length() > 0) out.println("Get/view the graph's image file (" + suffix + ").

"); else out.println("The graph image file is empty."); } // One last thing to do before exiting - copy the RDF to a file if (saveRDF) copyRDFStringToFile(tmpDir, rdf); } catch (Exception e) { System.err.println("Exception generating graph: " + e.getMessage()); } } /* * Search the given string for substring "key" * and if it is found, replace it with string "replacement" * *@param input the input string *@param key the string to search for *@param replacement the string to replace all occurences of "key" *@return if no substitutions are done, input is returned; otherwise * a new string is returned. */ public static String replaceString(String input, String key, String replacement) { try { RE re = new RE(key); return re.subst(input, replacement); } catch (Exception e) { return input; } } /* * Print the document's header info * *@param out the servlet's output stream */ private void printDocumentHeader (PrintWriter out) { try { out.println( "" + "" + "RDF Validator" + "" + "" + "" + ""); } catch (Exception e) { System.err.println("Exception (printDocumentHeader): " + e.getMessage()); } } /* * Print the rdf listing * *@param out the servlet's output stream *@param rdf the RDF code *@param needCR if true, add a CarriageReturn to the output; if false, * do not add it */ private void printListing (PrintWriter out, String rdf, boolean needCR) { try { out.println("
" + "

The original RDF/XML document

" + "
");

            String s = replaceString(rdf, "<", "<");
            
            // Now output the RDF one line at a time with line numbers
            int lineNum = 1;
            int nl = 0;
            String terminator = needCR?"\n":"";
            do {
                String tok;
                nl = s.indexOf('\n');
                if ( nl == -1 ) {
                    tok = s;
                } else {
                    tok = s.substring(0,nl);
                    s = s.substring(nl+1);
                }
                out.print("" + lineNum +
                          ": " + tok + terminator);
                lineNum++;
            } while ( nl != -1 );

            out.println("
"); } catch (Exception e) { System.err.println("Exception (printListing): " + e.getMessage()); } } /* * Print the header for the triple listing * *@param out the servlet's output stream *@param nTriples if true, output is N-Triples syntax */ private void printTripleTableHeader (PrintWriter out, boolean nTriples) { try { if (nTriples) { out.println("

Triples of the Data Model in " + "" + "N-Triples Format (Sub, Pred, Obj)

" + "
");
            } else {
                out.println("
"); out.println("

Triples of the Data Model

"); out.println("" + "" + "" + "" + "" + ""); } } catch (Exception e) { System.err.println("Exception (printTripleTableHeader): " + e.getMessage()); } } /* * Print the footer info for the triple listing * *@param out the servlet's output stream *@param nTriples if true, output is N-Triples syntax */ private void printTripleTableFooter (PrintWriter out, boolean nTriples) { try { if (nTriples) out.println(""); else out.println("
NumberSubjectPredicateObject
"); } catch (Exception e) { System.err.println("Exception (printTripleTableFooter): " + e.getMessage()); } } /* * Print the document's footer info * *@param out the servlet's output stream *@param rdf the RDF code */ private void printDocumentFooter (PrintWriter out, String rdf) { try { String s; s = "
" + "

Feedback

" + "

If you suspect the parser is in error, please enter an explanation below and then press the Submit problem report button, to mail the report (and listing) to " + MAIL_TO + "

" + "
" + ""; out.println(s); out.println("", ">"); s1 = replaceString(s1, "\"", """); out.println(s1); } out.println("\"\\>"); out.println("" + "
"); } catch (Exception e) { System.err.println("Exception (printDocumentFooter): " + e.getMessage()); } } /* * Servlet's get info method */ public String getServletInfo () { return "Servlet wrapper for the ARP RDF parser. This is revision " + REVISION; } /* * Servlet's init method * *@param config the servlet's configuration object *@throws ServletException */ public void init(ServletConfig config) throws ServletException { super.init (config); // Cache the parameters m_ServletTmpDir = config.getInitParameter(SERVLET_TMP_DIR); // All of the Graph Viz paths extend from GRAPH_VIZ_ROOT String GraphVizRoot = config.getInitParameter(GRAPH_VIZ_ROOT); m_GraphVizPath = GraphVizRoot + "/" + config.getInitParameter(GRAPH_VIZ_PATH); m_GraphVizFontDir = GraphVizRoot + "/" + config.getInitParameter(GRAPH_VIZ_FONT_DIR); System.out.println("GRAPH_VIZ_ROOT = " + GraphVizRoot); System.out.println("GRAPH_VIZ_PATH = " + m_GraphVizPath); System.out.println("GRAPH_VIZ_FNTDIR = " + m_GraphVizFontDir); System.out.println("SERVLET_TMP_DIR = " + m_ServletTmpDir); if (m_ServletTmpDir == null || GraphVizRoot == null) { System.err.println ( "" + "

Servlet Initialization Error

" + "

One or more of the following parameters has not been initialized: " + SERVLET_TMP_DIR + "," + GRAPH_VIZ_ROOT + "," + GRAPH_VIZ_FONT_DIR + "," + GRAPH_VIZ_PATH + "." + "

" + ""); } } /* * Servlet's destroy info method */ public void destroy () { super.destroy (); } /* * Servlet's doGet info method - NOT supported * *@param req the request *@param res the response *@throws ServletException, IOException */ public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String sRDF = req.getParameter(TEXT); String sURI = req.getParameter(URI); if (sURI == null && sRDF == null) { res.setContentType ("text/html;charset=utf-8"); PrintWriter out = res.getWriter (); out.println("

Data Error

" + "Must specify the RDF (RDF is a string) or the URI parameter." + ""); return; } try { process(req, res, (sRDF != null) ? java.net.URLDecoder.decode(sRDF) : null, (sURI != null) ? java.net.URLDecoder.decode(sURI) : null); } catch (Exception e) { System.err.println("Exception: URLDecoder.decode()"); } } /* * Convenience method to convert some String wrongly read in with iso-8859-1 to utf-8 * *@param str the String (input and output) */ private String ISO88591toUTF8 (String str) throws java.io.UnsupportedEncodingException { return new String(str.getBytes("iso-8859-1"), "utf-8"); } /* * Servlet's doPost method * *@param req the request *@param res the response *@throws ServletException, IOException, java.io.UnsupportedEncodingException */ public void doPost (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // String encoding = req.getCharacterEncoding(); // if (encoding == null) { // req.setCharacterEncoding("UTF-8"); // } String sRDF = ISO88591toUTF8 (req.getParameter (TEXT)); String sURI = ISO88591toUTF8 (req.getParameter (URI)); if (sURI == null && sRDF == null) { res.setContentType ("text/html;charset=utf-8"); PrintWriter out = res.getWriter (); out.println("

Neither the RDF or an URI was specified" + "and one of them must be specified.

"); return; } process(req,res,sRDF, sURI); } /* * Output a Resource in NTriples syntax * *@param out the servlet's output stream *@param r the Resource to output */ static private void printResource(PrintWriter out, AResource r) { if (r.isAnonymous() ) out.print("_:j" + r.getAnonymousID() + " "); else out.print("<" + r.getURI() + "> "); } /* * Convert to Hex and padd left with zeroes * *@param in the integer to convert and padd *@param in the length of the result *@return the padded string */ // MJD: is there an easier way to do this? static private String hexPadd (int number, int length) { String t = Integer.toHexString(number).toUpperCase(); int hexlength = t.length(); if ( hexlength > length ) { // too long, truncate hexlength = length; } int zerolength = length - hexlength; String r = ""; for (int i=0; i < zerolength; i++) { r += "0"; } for (int i=0; i < hexlength; i++) { r += t.charAt(i); } return r; } /* * Output a Literal in NTriples syntax * *@param out the servlet's output stream *@param l the Literal to output */ static private void printNTripleLiteral(PrintWriter out, ALiteral l) { out.print("\""); char ar[] = l.toString().toCharArray(); for (int i=0;i= 32 && ar[i] <= 127 ) out.print(ar[i]); else if ( ar[i] < 0xD800 || ar[i] >= 0xE000) out.print("\\u" + hexPadd(ar[i], 4) ); else { // deal with surrogates // check for correct surrogate pair // this code should probably move somewhere else: // check when we get the input if ( ar[i] >= 0xDC00 ) { out.print("{{{error: lone low surrogate}}}"); } else if ( ++i >= ar.length ) { out.print("{{{error: lone surrogate at end of string}}}"); } else if ( ar[i] < 0xDC00 || ar[i] >= 0xE000 ) { out.print("{{{error: high surrogate not followed by low surrogate}}}"); } // no errors, actually print else { int scalarvalue = 0x10000 + (ar[i-1] * 1024) + ar[i]; out.print("\\U" + hexPadd(scalarvalue, 8) ); } } } } out.print("\" "); } /* * Control point for outputing an triple in NTriple syntax * *@param out the servlet's output stream *@param subj the subject *@param pred the predicate *@param objRes the object as a Resource (may be null) *@param objLit the object as a Literal (may be null) */ static private void printNTriple(PrintWriter out, AResource subj, AResource pred, AResource objRes, ALiteral objLit) { printResource(out, subj); printResource(out, pred); if (objRes != null) printResource(out, objRes); else printNTripleLiteral(out, objLit); out.println("."); } /* * Create a HTML anchor from the URI or anonNode of the * given Resource * *@param r the Resource *@return the string as an HTML anchor */ static private String addAnchor(AResource r) { if (r.isAnonymous()) return ANON_NODE + r.getAnonymousID(); else return "" + r.getURI() + ""; } /* * Output a triple as a row in HTML * *@param out the servlet's output stream *@param subj the subject *@param pred the predicate *@param objRes the object as a Resource (may be null) *@param objLit the object as a Literal (may be null) *@param num the statement number */ static private void printTableRow(PrintWriter out, AResource subj, AResource pred, AResource objRes, ALiteral objLit, int num) { out.println("" + num + ""); out.println("" + addAnchor(subj) + ""); out.println("" + addAnchor(pred) + ""); if (objRes != null) out.println("" + addAnchor(objRes) + ""); else { out.println(""); String s1 = objLit.toString().trim(); s1 = replaceString(s1, "<", "<"); s1 = replaceString(s1, ">", ">"); out.println(s1); out.println(""); } out.println(""); } private static class SH implements StatementHandler { PrintWriter out; PrintWriter pw; boolean isNTriples; boolean printTriples; boolean printGraph; boolean anonNodesEmpty; int numStatements; int numLiterals; Hashtable subjects; int numSubjects; /* * Constructuor for the StatementHandler. The primary * responsiblitly is to cache init variables * *@param out the servlet's PrintWriter *@param pw the Dot file's PrintWriter * syntax; otherwise use HTML syntax *@param isNTriples if true, output using the NTriples *@param printTriples if true, print the triples *@param printGraph if true, create the graph file *@param printGraph if true, anonomyous nodes should be empty */ public SH(PrintWriter out, PrintWriter pw, boolean isNTriples, boolean printTriples, boolean printGraph, boolean anonNodesEmpty) { this.out = out; this.pw = pw; this.isNTriples = isNTriples; this.printTriples = printTriples; this.printGraph = printGraph; this.anonNodesEmpty = anonNodesEmpty; this.numStatements = 0; this.numLiterals = 0; this.subjects = new Hashtable(); this.numSubjects = 0; } /* * Generic handler for a Resource/Resource/Resource triple (S/P/O). * Dispatches to the methods that do the real work. * *@param subj the subject *@param pred the predicate *@param obj the object (as a Resource) */ public void statement(AResource subj, AResource pred, AResource obj) { if (printTriples) statementResource(subj, pred, obj); if (printGraph) statementDotResource(subj, pred, obj); } /* * Generic handler for a Resource/Resource/Resource triple (S/P/O). * Dispatches to the methods that do the real work. * *@param subj the subject *@param pred the predicate *@param obj the object (as a Literal) */ public void statement(AResource subj, AResource pred, ALiteral lit) { numLiterals++; if (printTriples) statementLiteral(subj, pred, lit); if (printGraph) statementDotLiteral(subj, pred, lit); } /* * Handler for a Resource/Resource/Resource triple (S/P/O) * Outputs the given triple using NTriples or HTML syntax. * *@param subj the subject *@param pred the predicate *@param obj the object (as a Resource) */ public void statementResource(AResource subj, AResource pred, AResource obj) { numStatements++; if (this.isNTriples) printNTriple(out, subj, pred, obj, null); else printTableRow(out, subj, pred, obj, null, this.numStatements); } /* * Handler for a Resource/Resource/Literal triple (S/P/O) * Outputs the given triple using NTriples or HTML syntax. * *@param subj the subject *@param pred the predicate *@param obj the object (as a Literal) */ public void statementLiteral(AResource subj, AResource pred, ALiteral lit) { numStatements++; if (this.isNTriples) printNTriple(out, subj, pred, null, lit); else printTableRow(out, subj, pred, null, lit, this.numStatements); } /* * Print the first part of a triple's Dot file. See below for * more info. This is the same regardless if the triple's * object is a Resource or a Literal * *@param subj the subject */ public void printFirstPart(AResource subj) { if (subj.isAnonymous()) { if (this.anonNodesEmpty) { Integer n = (Integer) subjects.get(subj.getAnonymousID()); if (n == null) { this.numSubjects++; subjects.put(subj.getAnonymousID(), new Integer(this.numSubjects)); this.pw.println("\"" + ANON_NODE + subj.getAnonymousID() + "\" [label=\" \"];"); } } this.pw.print("\"" + ANON_NODE + subj.getAnonymousID()); } else { this.pw.println("\"" + subj.getURI() + "\" [URL=\"" + subj.getURI() + "\"];"); this.pw.print("\"" + subj.getURI()); } } /* * Handler for a Resource/Resource/Resource triple (S/P/O). * Outputs the given triple using Dot syntax. * * Each triple will be output in three lines of DOT code as * follows (not including the complication of anon nodes * and the possiblity that the anon nodes may be named * with an empty string): * * 1. "" [URL="]; * 2. "" -> "" [label="",URL=""]; * 3. "" [URL=""]; * *@param subj the subject *@param pred the predicate *@param obj the object (as a Resource) */ public void statementDotResource(AResource subj, AResource pred, AResource obj) { if (this.pw == null) return; printFirstPart(subj); this.pw.print("\" -> "); if (obj.isAnonymous()) { if (this.anonNodesEmpty) { this.pw.println("\"" + ANON_NODE + obj.getAnonymousID() + "\" [label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];"); } else { this.pw.println("\"" + ANON_NODE + obj.getAnonymousID() + "\" [label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];"); } } else { this.pw.println("\"" + obj.getURI() + "\" [label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];"); this.pw.println("\"" + obj.getURI() + "\" [URL=\"" + obj.getURI() + "\"];"); } } /* * Handler for a Resource/Resource/Literal triple (S/P/O). * Outputs the given triple using Dot syntax. * * Each triple will be output in three lines of DOT code as * follows (not including the complication of anon nodes * and the possiblity that the anon nodes may be named * with an empty string): * * 1. "" [URL="]; * 2. "" -> "" [label="",URL=""]; * 3. "" [shape="box"]; * *@param subj the subject *@param pred the predicate *@param obj the object (as a Literal) */ public void statementDotLiteral(AResource subj, AResource pred, ALiteral lit) { if (this.pw == null) return; printFirstPart(subj); // Same as Res/Res/Res /* * Before outputing the object (Literal) do the following: * * o GraphViz/DOT cannot handle embedded line terminators characters * so they must be replaced with spaces * o Limit the number of chars to make the graph legible * o Escape double quotes */ String s1 = new String(lit.toString()); s1 = s1.replace('\n', ' '); s1 = s1.replace('\f', ' '); s1 = s1.replace('\r', ' '); if (s1.indexOf('"') != -1) s1 = replaceString(s1, "\"", "\\\""); // Anything beyond 80 chars makes the graph too large String tmpObject; if (s1.length() >= 80) tmpObject = s1.substring(0, 80) + " ..."; else tmpObject = s1.substring(0, s1.length()); // Create a temporary label for the literal so that if // it is duplicated it will be unique in the graph and // thus have its own node. String tmpName = "Literal_" + Integer.toString(this.numLiterals); this.pw.print("\" -> \"" + tmpName); this.pw.println("\" [label=\"" + pred.getURI() + "\",URL=\"" + pred.getURI() + "\"];"); this.pw.println("\"" + tmpName + "\" [shape=box,label=\"" + tmpObject + "\"];"); } } private void printErrorMessages(PrintWriter out, SaxErrorHandler eh) { try { String s; s = eh.getFatalErrors(); if (s != null && s.length() >= 1) out.println("

Fatal Error Messages

" + s); s = eh.getErrors(); if (s != null && s.length() >= 1) out.println("

Error Messages

" + s); s = eh.getWarnings(); if (s != null && s.length() >= 1) out.println("

Warning Messages

" + s); } catch (Exception e) { System.err.println(SERVLET_NAME + ": Error printing error messages."); } } /* * Initialize the graph output file. If an error occurs, this * function will print an error message. * *@param out the servlet's output stream *@req the servlet request object *@return the File object for the graph file; null if an error occurs */ private File initGraphFile(PrintWriter out, HttpServletRequest req) { try { // Stop if any of the parameters are missing if (m_ServletTmpDir == null || m_GraphVizPath == null || m_GraphVizFontDir == null) { // Put the paths in a comment in the returned content out.println(""); out.println("

Servlet initialization failed

"); out.println("Please send a message to " + MAIL_TO + " and mention this problem."); return null; } } catch (Exception e) { System.err.println("Unable to create a temporary graph file. A graph cannot be generated."); return null; } File dotFile = null; // Must generate a unique file name that the DOT handler will use dotFile = createTempFile(m_ServletTmpDir, TMP_FILE_PREFIX, SUFFIX_DOT); if (dotFile == null) { out.println("

Failed to create a temporary graph file. A graph cannot be generated.

"); return null; } return dotFile; } /* * Check if the given URI is supported or not * *@param out the servlet's output stream *@param uri the URI to check *@return true if the URI is supported; false otherwise */ private boolean isURISupported(PrintWriter out, String uri) { try { if (uri.length() >= 4 && uri.substring(0,4).equalsIgnoreCase("file")) { out.println("

file URI Schemes are NOT Supported

"); out.println("URIs from the 'file' URI scheme are not supported by this servlet."); return false; } } catch (Exception e) { System.err.println("Exception in isURISupported."); return false; } return true; } /* * Handle the servlets doGet or doPut request * *@param req the servlet's request *@param res the servlet's response *@throws SevletException, IOException */ private void process(HttpServletRequest req, HttpServletResponse res, String sRDF, String sURI) throws ServletException, IOException { res.setContentType ("text/html;charset=utf-8"); PrintWriter out = res.getWriter (); String sSaveRDF = req.getParameter (SAVE_RDF); String sSaveDOTFile = req.getParameter (SAVE_DOT_FILE); String sFormat = req.getParameter (FORMAT); String sNTriples = req.getParameter (NTRIPLES); String sEmbedded = req.getParameter (EMBEDDED_RDF); String sTriplesAndGraph = req.getParameter (TRIPLES_AND_GRAPH); String sAnonNodesEmpty = req.getParameter (ANON_NODES_EMPTY); // Set the print flags boolean printTriples = true; boolean printGraph = true; if (sTriplesAndGraph != null) { if (sTriplesAndGraph.equals(PRINT_TRIPLES)) printGraph = false; if (sTriplesAndGraph.equals(PRINT_GRAPH)) printTriples = false; } // Determine if printing the triples and/or graph boolean anonNodesEmpty = (sAnonNodesEmpty != null) ? true : false; boolean nTriples = (sNTriples != null) ? true : false; // ARP parser has embedded = true by default so if user // wants embedding, must set it to false boolean embedded = (sEmbedded != null) ? false : true; String sError = null; InputStream in = null; String xmlBase = DEFAULT_NAMESPACE; printDocumentHeader (out); if (sURI != null && sURI.length() >= 1) { // First check for unsupported URIs if (!isURISupported(out, sURI)) { printDocumentFooter(out, null); return; } xmlBase = sURI; try { File ff = new File(sURI); in = new FileInputStream(ff); } catch (Exception ignore) { try { URL url; url=new URL(sURI); in = url.openStream(); sRDF = getByteStream(sURI); if (sRDF == null) sError = "error"; } catch (Exception e) { sError = "error"; } } } if (sError != null) { out.println("

RDF Load Error

"); out.println("An attempt to load the RDF from URI '" + sURI + "' failed. (The URI may not exist or the server is down.)"); printDocumentFooter(out, null); return; } PrintWriter pw = null; // The writer for the graph file File dotFile = null; // The graph file if (sFormat != null && printGraph) { dotFile = initGraphFile(out, req); if (dotFile == null) // Assume error has been reported return; // Create a PrintWriter for the DOT handler FileWriter fw = new FileWriter(dotFile); if (fw != null) pw = new PrintWriter(fw); if (pw != null) // Add the graph header processGraphParameters (req, pw); } // Create the StatementHandler - it will handle triples for // the table/ntriples and the graph file SH sh = new SH(out, pw, nTriples, printTriples, printGraph, anonNodesEmpty); // Create the ErrorHandler SaxErrorHandler errorHandler = new SaxErrorHandler(out, false); // Create and initialize the parser ARP parser = new com.hp.hpl.jena.rdf.arp.ARP(); parser.setErrorHandler(errorHandler); parser.setStatementHandler(sh); parser.setEmbedding(embedded); printListing (out, sRDF, sURI != null && sURI.length() >= 1); if (printTriples) printTripleTableHeader (out, nTriples); try { if (sURI != null && sURI.length() >= 1) { parser.load(in, xmlBase); } else { StringReader sr = new StringReader (sRDF); parser.load(sr, xmlBase); } } catch (IOException ioe) { sError = "IOError parsing: " + sURI + ": " + ioe.toString(); } catch (Exception ex) { sError = "Exception parsing: " + sURI + ": " + ex.toString(); } if (printTriples) printTripleTableFooter(out, nTriples); printErrorMessages(out, errorHandler); if (sError != null) { out.println ("

Parser Loading Error

"); out.println (sError); printDocumentFooter(out, null); return; } res.flushBuffer(); if (sFormat != null && printGraph) { generateGraph(out, pw, dotFile, sRDF, req, sFormat, (sSaveRDF != null) ? true : false, (sSaveDOTFile != null && sSaveDOTFile.equals ("on") ? true : false)); } if (sURI != null && sURI.length() >= 1) printDocumentFooter(out, null); else printDocumentFooter(out, sRDF); } }