Annotation of java/classes/org/w3c/rdf/examples/SiRPACServlet.java, revision 1.12
1.1 barstow 1: /**
2: * SiRPACServlet - Simple RDF Parser & Compiler Servlet wrapper
3: *
4: * Copyright © World Wide Web Consortium, (Massachusetts Institute of
5: * Technology, Institut National de Recherche en Informatique et en
6: * Automatique, Keio University).
7: *
8: * All Rights Reserved.
9: *
10: * Please see the full Copyright clause at
11: * <http://www.w3.org/Consortium/Legal/copyright-software.html>
12: *
1.3 barstow 13: * This servlet is a wrapper for the SiRPAC RDF parser. The servlet
1.7 barstow 14: * expects the following variables through the POST method:
1.3 barstow 15: *
1.4 barstow 16: * 1. "RDF" - the RDF/XML document
17: * 2. "BAGS" - if "on", each Description should have its own Bag;
18: * the default is not to do this.
1.11 barstow 19: * 3. "STREAM" if "on", the stream mode is turned off so that aboutEach
1.10 barstow 20: * and aboutEachPrefix are supported.
1.1 barstow 21: *
1.7 barstow 22: * @author Art Barstow <barstow@w3.org>
1.1 barstow 23: *
1.7 barstow 24: * The graphics package is AT&T's GraphVis tool.
1.1 barstow 25: */
26:
27: package org.w3c.rdf.examples;
28:
29: import java.io.*;
30: import java.util.StringTokenizer;
31: import java.util.Enumeration;
32: import javax.servlet.*;
33: import javax.servlet.http.*;
34:
35: import org.xml.sax.InputSource;
36: import org.xml.sax.Parser;
37: import org.xml.sax.SAXException;
38: import org.xml.sax.helpers.*;
39:
40: import org.w3c.rdf.model.*;
41: import org.w3c.rdf.syntax.*;
42: import org.w3c.rdf.syntax.RDFConsumer;
43: import org.w3c.rdf.util.xml.DumpConsumer;
44: import org.w3c.rdf.util.xml.ErrorStore;
45: import org.w3c.rdf.implementation.model.StatementImpl;
46: import org.w3c.rdf.implementation.model.NodeFactoryImpl;
47: import org.w3c.rdf.implementation.syntax.sirpac.*;
48:
49: public class SiRPACServlet extends HttpServlet
50: {
1.12 ! barstow 51: final static public String REVISION = "$Id: SiRPACServlet.java,v 1.11 2000/10/17 22:58:42 barstow Exp $";
1.1 barstow 52:
1.7 barstow 53: // The email address for bug reports
1.4 barstow 54: private static final String MAIL_TO = "barstow@w3.org";
1.10 barstow 55:
56: // Names of the POST parameters
57: // The XML'ized RDF
58: private static final String POST_TEXT = "RDF";
59: // Flag for turning on treating each Description as a bag
60: private static final String POST_BAG = "BAGS";
61: // Flag for turning off SiRPAC's stream parsing mode
62: private static final String POST_STREAM_MODE = "STREAM";
1.3 barstow 63:
64: // Names of the servlet's parameters
1.5 barstow 65: private static final String SIRPAC_TMP_DIR = "SIRPAC_TMP_DIR";
66: private static final String GRAPH_VIZ_ROOT = "GRAPH_VIZ_ROOT";
67: private static final String GRAPH_VIZ_PATH = "GRAPH_VIZ_PATH";
68: private static final String GRAPH_VIZ_LIB_DIR = "GRAPH_VIZ_LIB_DIR";
69: private static final String GRAPH_VIZ_FONT_DIR = "GRAPH_VIZ_FONT_DIR";
1.3 barstow 70:
71: // Variables for the servlet's parameters
1.5 barstow 72: private static String m_SiRPACTmpDir = null;
73: private static String m_GraphVizPath = null;
74: private static String m_GraphVizFontDir = null;
75: private static String m_GraphVizLibDir = null;
1.4 barstow 76:
77: // Names of environment variable need by GraphVis
78: private static String DOTFONTPATH = "DOTFONTPATH";
79: private static String LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
80:
81: // Names used for temporary files
82: private static final String TMP_FILE_PREFIX = "sirpac_";
83: private static final String TMP_DIR_SUFFIX = ".tmp";
84: private static final String DOT_SUFFIX = ".dot";
85: private static final String GIF_SUFFIX = ".gif";
1.3 barstow 86:
1.6 barstow 87: // Default GraphViz parameter names and their default values
88: private static final String NODE_COLOR = "NODE_COLOR";
89: private static final String DEFAULT_NODE_COLOR = "black";
90:
91: private static final String NODE_TEXT_COLOR = "NODE_TEXT_COLOR";
92: private static final String DEFAULT_NODE_TEXT_COLOR = "black";
93:
94: private static final String EDGE_COLOR = "EDGE_COLOR";
95: private static final String DEFAULT_EDGE_COLOR = "black";
96:
97: private static final String EDGE_TEXT_COLOR = "EDGE_TEXT_COLOR";
98: private static final String DEFAULT_EDGE_TEXT_COLOR = "black";
99:
100: private static final String ORIENTATION = "ORIENTATION";
101: private static final String DEFAULT_ORIENTATION = "TB"; // Top to Bottom
102:
103: private static final String FONT_SIZE = "FONT_SIZE";
104: private static final String DEFAULT_FONT_SIZE = "10";
105:
106: // Fonts are not currently configurable
107: private static final String DEFAULT_FONT = "arial";
108:
1.8 barstow 109: // Servlet name
110: private static final String SERVLET_NAME = "SiRPACServlet";
111:
1.3 barstow 112: // The parser
113: private SiRPAC m_sirpac = null;
114: // The error handler
115: private ErrorStore m_errorHandler;
1.1 barstow 116:
1.3 barstow 117: /*
1.4 barstow 118: * Create a File object in the m_SiRPACTmpDir directory
1.3 barstow 119: *
1.4 barstow 120: *@param directory the file's directory
121: *@param prefix the file's prefix name (not its directory)
122: *@param suffix the file's suffix or extension name
123: *@return a File object if a temporary file is created; null otherwise
1.3 barstow 124: */
1.4 barstow 125: private File createTempFile (String directory, String prefix, String suffix) {
126: File f;
127: try {
128: File d = new File(directory);
129: f = File.createTempFile(prefix, suffix, d);
130: } catch (Exception e) {
131: return null;
132: }
133: return f;
134: }
135:
136: /*
137: * Invokes the GraphVis program to create a GIF image from the
138: * the given DOT data file
139: *
140: *@param dotFileName the name of the DOT data file
141: *@param gifFileName the name of the GIF data file
142: *@return true if success; false if any failure occurs
143: */
144: private boolean generateGifFile(String dotFileName, String gifFileName) {
1.5 barstow 145: String environment[] = {DOTFONTPATH + "=" + m_GraphVizFontDir,
146: LD_LIBRARY_PATH + "=" + m_GraphVizLibDir};
1.4 barstow 147:
1.5 barstow 148: String cmdArray[] = {m_GraphVizPath, "-Tgif", "-o", gifFileName, dotFileName};
1.4 barstow 149:
150: Runtime rt = Runtime.getRuntime();
151: try {
152: Process p = rt.exec(cmdArray, environment);
153: p.waitFor();
154: } catch (Exception e) {
155: return false;
156: }
157:
158: return true;
1.3 barstow 159: }
1.1 barstow 160:
1.3 barstow 161: /*
1.6 barstow 162: * Returns a parameter from a request or the parameter's default
163: * value.
164: *
165: *@param req a Servlet request
166: *@return if the request contains the specfied parameter its value
167: * in the request is returned; otherwise its default value is
168: * returned
169: */
170: private String getParameter(HttpServletRequest req, String param, String defString) {
171: String s = req.getParameter(param);
172: return (s == null) ? defString : s;
173: }
174:
175: /*
176: * If the request contains any graph-related parameters, pass them
177: * to the graph consumer for handling
178: *
179: *@param req the response
180: *@param consumer the GraphViz consumer
181: */
182: private void processGraphParameters (HttpServletRequest req, GraphVizDumpConsumer consumer) {
183: // Look for colors
184:
185: String s;
186:
187: String nodeColor = getParameter (req, NODE_COLOR, DEFAULT_NODE_COLOR);
188: String nodeTextColor = getParameter (req, NODE_TEXT_COLOR, DEFAULT_NODE_TEXT_COLOR);
189: String edgeColor = getParameter (req, EDGE_COLOR, DEFAULT_EDGE_COLOR);
190: String edgeTextColor = getParameter (req, EDGE_TEXT_COLOR, DEFAULT_EDGE_TEXT_COLOR);
191: String fontSize = getParameter (req, FONT_SIZE, DEFAULT_FONT_SIZE);
192:
193: // Orientation must be either
194: String orientation = req.getParameter (ORIENTATION);
195: if (orientation.equals("Left to Right"))
196: orientation = "LR";
197: else
198: orientation = DEFAULT_ORIENTATION;
199:
200: // Add an attribute for all of the graph's nodes
201: consumer.addGraphAttribute("node [fontname=" + DEFAULT_FONT +
202: ",fontsize=" + fontSize +
203: ",color=" + nodeColor +
204: ",fontcolor=" + nodeTextColor + "]");
205:
206: // Add an attribute for all of the graph's edges
207: consumer.addGraphAttribute("edge [fontname=" + DEFAULT_FONT +
208: ",fontsize=" + fontSize +
209: ",color=" + edgeColor +
210: ",fontcolor=" + edgeTextColor + "]");
211:
212: // Add an attribute for the orientation
213: consumer.addGraphAttribute("rankdir=" + orientation + ";");
214: }
215:
216: /*
1.3 barstow 217: * Generate a graph of the RDF data model
218: *
1.4 barstow 219: *@param out the servlet's output stream
1.6 barstow 220: *@param rdf the RDF text
221: *@param req a Servlet request
1.3 barstow 222: */
223: private void generateGraph (ServletOutputStream out, String rdf, HttpServletRequest req) {
1.2 barstow 224: try {
225: out.println("<hr title=\"visualisation\">");
1.3 barstow 226: out.println("<h3>Graph of the data model</h3>");
227:
1.4 barstow 228: // Stop if any of the parameters are missing
1.5 barstow 229: if (m_SiRPACTmpDir == null || m_GraphVizPath == null ||
230: m_GraphVizFontDir == null || m_GraphVizLibDir == null) {
1.8 barstow 231:
232: // Put the paths in a comment in the returned content
233: out.println("<!-- SIRPAC TMP = " + m_SiRPACTmpDir);
234: out.println("GRAPH VIZ = " + m_GraphVizPath);
235: out.println("GRAPH LIB = " + m_GraphVizLibDir);
236: out.println("GRAPH FON = " + m_GraphVizFontDir + " -->");
237:
1.3 barstow 238: out.println("Servlet initialization failed. A graph cannot be generated.");
239: return;
240: }
241:
1.4 barstow 242: // The temporary directory
243: String tmpDir = m_SiRPACTmpDir;
1.3 barstow 244:
1.4 barstow 245: // Must generate a unique file name that the DOT consumer
246: // will use
247: File dotFile = createTempFile(tmpDir, TMP_FILE_PREFIX, DOT_SUFFIX);
248: if (dotFile == null) {
249: out.println("Failed to create a temporary DOT file. A graph cannot be generated.");
1.3 barstow 250: return;
251: }
252:
253: // Create a PrintWriter for the GraphViz consumer
1.4 barstow 254: FileWriter fw = new FileWriter(dotFile);
1.3 barstow 255: PrintWriter pw = new PrintWriter(fw);
256:
257: // Run the parser using the DOT consumer to capture
258: // the output in a file
259: StringReader sr = new StringReader (rdf);
260: InputSource is = new InputSource (sr);
261: GraphVizDumpConsumer consumer = new GraphVizDumpConsumer(pw);
262:
1.6 barstow 263: // Process any graph-related parameters in the request
264: processGraphParameters(req, consumer);
265:
1.3 barstow 266: try {
267: m_sirpac.parse(is, consumer);
268: } catch (Exception e) {
269: out.println("An attempt to generate the graph data failed ("
270: + e.getMessage() + ").");
1.4 barstow 271: pw.close();
272: dotFile.delete();
1.3 barstow 273: return;
274: }
275:
1.4 barstow 276: // Must close the DOT input file so the GraphViz can
277: // open and read it
278: pw.close();
279:
280: // Must generate a unique file name for the GIF file
281: // that will be created
282: File gifFile = createTempFile(tmpDir, TMP_FILE_PREFIX, GIF_SUFFIX);
283: if (gifFile == null) {
284: out.println("Failed to create a temporary GIF file. A graph cannot be generated.");
285: dotFile.delete();
286: return;
287: }
288:
1.3 barstow 289: // Pass the DOT data file to the GraphViz dot program
1.4 barstow 290: // so it can create a GIF image of the data model
291: String dotFileName = dotFile.getAbsolutePath();
292: String gifFileName = gifFile.getAbsolutePath();
293:
294: if (!generateGifFile(dotFileName, gifFileName)) {
295: out.println("An attempt to create a graph failed.");
296: dotFile.delete();
297: gifFile.delete();
298: return;
299: }
1.3 barstow 300:
1.7 barstow 301: // Cleanup
302: dotFile.delete();
1.3 barstow 303:
1.9 barstow 304: // NOTE: Cannot delete the GIF file here because its
305: // pathname is returned to the client
1.8 barstow 306: String imagePath = SERVLET_NAME +
1.7 barstow 307: TMP_DIR_SUFFIX + File.separator +
308: gifFile.getName();
1.2 barstow 309:
1.4 barstow 310: if (gifFile.length() > 0)
311: out.println("<img src=\"" + imagePath + "\"/>");
312: else
313: out.println("The graph image file is empty.");
1.2 barstow 314:
315: } catch (Exception e) {
316: System.err.println("Exception: " + e.getMessage());
317: }
318: }
319:
320: /*
1.3 barstow 321: * Search the given string for substring "key"
1.2 barstow 322: * and if it is found, replace it with string "replacement"
323: *
1.4 barstow 324: *@param input the input string
325: *@param key the string to search for
326: *@param replacement the string to replace all occurences of "key"
1.2 barstow 327: *@return if no substitutions are done, input is returned; otherwise
328: * a new string is returned.
329: */
1.12 ! barstow 330: public static String replaceString(String input, String key, String replacement) {
1.2 barstow 331: StringBuffer sb = new StringBuffer("");
332: StringTokenizer st = new StringTokenizer(input, key);
333:
334: // Must handle the case where the input string begins with the key
335: if (input.startsWith(key))
336: sb = sb.append(replacement);
337: while (st.hasMoreTokens()) {
338: sb = sb.append(st.nextToken());
339: if (st.hasMoreTokens())
340: sb = sb.append(replacement);
341: }
342: if (sb.length() >= 1)
343: return sb.toString();
344: else
345: return input;
346: }
347:
1.3 barstow 348: /*
349: * Print the document's header info
350: *
351: *@param out the servlet's output stream
352: */
1.1 barstow 353: private void printDocumentHeader (ServletOutputStream out) {
354:
355: try {
356:
357: out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"");
358: out.println(" \"http://www.w3.org/TR/REC-html40/loose.dtd\">");
359: out.println("<HTML><HEAD>");
360: out.println("<TITLE>RDF creation</TITLE>");
361: out.println("<LINK HREF=\"rdf.css\" REL=\"stylesheet\">");
362: out.println("</HEAD>");
363: out.println("<BODY>");
364:
365: } catch (Exception e) {
1.2 barstow 366: System.err.println("Exception: " + e.getMessage());
1.1 barstow 367: }
368: }
369:
1.3 barstow 370: /*
371: * Print the rdf listing
372: *
373: *@param out the servlet's output stream
374: *@param rdf the RDF code
375: */
1.1 barstow 376: private void printListing (ServletOutputStream out, String rdf) {
377: try {
378: out.println("<hr title=\"original source\">");
379: out.println("<h3>The original RDF/XML document</h3>");
380: out.println("<pre>");
381:
1.2 barstow 382: String s = replaceString(rdf, "<", "<");
383: StringTokenizer st = new StringTokenizer(s, "\n");
1.1 barstow 384:
385: // Now output the RDF one line at a time with line numbers
386: int lineNum = 1;
387: while (st.hasMoreTokens()) {
388: out.print ("<a name=\"" + lineNum + "\">" + lineNum +
389: "</a>: " + st.nextToken());
390: lineNum++;
391: }
392:
393: out.println("</pre>");
394: } catch (Exception e) {
395: System.err.println("Exception: " + e.getMessage());
396: }
397: }
398:
1.3 barstow 399: /*
400: * Print the header for the triple listing
401: *
402: *@param out the servlet's output stream
403: */
1.1 barstow 404: private void printTripleHeader (ServletOutputStream out) {
405: try {
406: out.println("<hr title=\"triples\">");
407: out.println("<h3>Triples of the data model</h3>");
408:
409: // The output for each triple will be pre-formatted
410: out.println("<pre>");
411: } catch (Exception e) {
412: System.err.println("Exception: " + e.getMessage());
413: }
414: }
415:
1.3 barstow 416: /*
417: * Print the footer info for the triple listing
418: *
419: *@param out the servlet's output stream
420: */
1.1 barstow 421: private void printTripleFooter (ServletOutputStream out) {
422: try {
423: out.println("</pre>");
424: } catch (Exception e) {
425: System.err.println("Exception: " + e.getMessage());
426: }
427: }
1.3 barstow 428:
429: /*
430: * Print the document's footer info
431: *
432: *@param out the servlet's output stream
433: *@param rdf the RDF code
434: */
1.1 barstow 435: private void printDocumentFooter (ServletOutputStream out, String rdf) {
436: try {
437:
438: out.println("<hr title=\"Problem reporting\">");
439: out.println("<h3>Feedback</h3>");
1.2 barstow 440: out.println("<p>If you suspect that SiRPAC produced an 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>");
1.1 barstow 441: out.println("<form enctype=\"text/plain\" method=\"post\" action=\"mailto:" + MAIL_TO + "\">");
442: out.println("<textarea cols=\"60\" rows=\"4\" name=\"report\"></textarea>");
1.2 barstow 443: out.println("<p><input type=\"hidden\" name=\"RDF\" value=\"<?xml version="1.0"?>");
1.1 barstow 444:
1.2 barstow 445: // The listing is being passed as a parameter so the '<'
446: // and '"' characters must be replaced with < and ",
447: // respectively
448: String s1 = replaceString(rdf, "<", "<");
449: String s2 = replaceString(s1, "\"", """);
450: out.println(s2 + "\">");
1.1 barstow 451:
452: out.println("<input type=\"submit\" value=\"Submit problem report\">");
453: out.println("</form>");
454: out.println("<hr><a href=\"/description\">Back</a> to main page.");
455: out.println("</BODY>");
456: out.println("</HTML>");
457:
458: } catch (Exception e) {
1.2 barstow 459: System.err.println("Exception: " + e.getMessage());
1.1 barstow 460: }
461:
462: }
463:
1.3 barstow 464: /*
465: * Servlet's get info method
466: */
1.1 barstow 467: public String getServletInfo () {
468: return "Servlet Wrapper for SiRPAC. This is revision " + REVISION;
469: }
470:
1.3 barstow 471: /*
472: * Servlet's init method
473: *
474: *@param config the servlet's configuration object
475: */
1.1 barstow 476: public void init(ServletConfig config) throws ServletException {
477: super.init (config);
478:
479: m_sirpac = new SiRPAC();
480: m_errorHandler = new ErrorStore();
1.3 barstow 481: m_sirpac.setErrorHandler(m_errorHandler);
1.1 barstow 482:
1.3 barstow 483: // Cache the parameters
484: m_SiRPACTmpDir = config.getInitParameter(SIRPAC_TMP_DIR);
1.5 barstow 485:
486: // All of the Graph Viz paths extend from GRAPH_VIZ_ROOT
487: String GraphVizRoot = config.getInitParameter(GRAPH_VIZ_ROOT);
488:
489: m_GraphVizPath = GraphVizRoot + "/" + config.getInitParameter(GRAPH_VIZ_PATH);
490: m_GraphVizFontDir = GraphVizRoot + "/" + config.getInitParameter(GRAPH_VIZ_FONT_DIR);
491: m_GraphVizLibDir = GraphVizRoot + "/" + config.getInitParameter(GRAPH_VIZ_LIB_DIR);
1.1 barstow 492: }
493:
1.3 barstow 494: /*
495: * Servlet's destroy info method
496: */
1.1 barstow 497: public void destroy () {
498: super.destroy ();
499: }
500:
1.3 barstow 501: /*
1.4 barstow 502: * Servlet's doGet info method - NOT supported
1.3 barstow 503: *
504: *@param req the request
505: *@param res the response
506: */
1.1 barstow 507: public void doGet (HttpServletRequest req, HttpServletResponse res)
508: throws ServletException, IOException {
1.3 barstow 509:
1.1 barstow 510: ServletOutputStream out = res.getOutputStream ();
511:
512: res.setContentType ("text/html");
513:
1.3 barstow 514: out.println ("<h1>GET is NOT supported!</h1>\n\n<p>Please send RDF through POST!</p>\n");
1.1 barstow 515: }
516:
1.3 barstow 517: /*
518: * Servlet's doPost method
519: *
520: *@param req the request
521: *@param res the response
522: */
1.1 barstow 523: public void doPost (HttpServletRequest req, HttpServletResponse res)
524: throws ServletException, IOException {
525:
526: ServletOutputStream out = res.getOutputStream ();
527:
1.10 barstow 528: String sRDF = req.getParameter (POST_TEXT);
529: String sBags = req.getParameter (POST_BAG);
530: String sStreamMode = req.getParameter (POST_STREAM_MODE);
1.1 barstow 531: StringReader sr = new StringReader (sRDF);
532: InputSource is = new InputSource (sr);
1.3 barstow 533: boolean error = false;
1.1 barstow 534: SiRPACServletDumpConsumer consumer = new SiRPACServletDumpConsumer();
1.9 barstow 535:
536: // Re-initialize the parser
537: m_sirpac = new SiRPAC();
538: m_errorHandler = new ErrorStore();
539: m_sirpac.setErrorHandler(m_errorHandler);
1.1 barstow 540:
541: printDocumentHeader (out);
542: printListing (out, sRDF);
543: printTripleHeader (out);
544:
545: try {
1.3 barstow 546: // Override the default triple output handler
1.1 barstow 547: consumer.setOutputStream(out);
548:
1.6 barstow 549: // Toggle Bag handling - always false unless explicitly
550: // included in the request
551: m_sirpac.createBags (false);
1.1 barstow 552: if (sBags != null && sBags.equals ("on"))
553: m_sirpac.createBags (true);
1.10 barstow 554:
555: // Set parser's streaming mode
1.11 barstow 556: if (sStreamMode != null && sStreamMode.equals ("on"))
1.10 barstow 557: m_sirpac.setStreamMode (false);
1.1 barstow 558:
559: m_sirpac.parse(is, consumer);
560:
1.12 ! barstow 561: printTripleFooter(out);
! 562:
1.3 barstow 563: generateGraph(out, sRDF, req);
1.2 barstow 564:
1.1 barstow 565: } catch (SAXException e) {
1.3 barstow 566: error = true;
1.1 barstow 567: } catch (Exception e) {
1.3 barstow 568: error = true;
1.1 barstow 569: e.printStackTrace ();
570: }
571:
572:
573: res.setContentType ("text/html");
1.3 barstow 574:
575: if (error) {
1.12 ! barstow 576: printTripleFooter(out);
1.1 barstow 577: out.println ("<h1>Errors during parsing</h1>\n");
578: out.println ("<pre>\n");
1.2 barstow 579:
580: // Make the line number a link to the listing
1.1 barstow 581: out.println ("Fatal error: " + m_errorHandler.getErrorMessage());
582: out.println (" (Line number = " + "<a href=\"#" +
583: m_errorHandler.getLineNumber() + "\">" +
584: m_errorHandler.getLineNumber() + "</a>" +
585: ", Column number = " +
586: m_errorHandler.getColumnNumber() + ")");
587:
588: out.println ("</pre>\n\n");
589: }
590:
591: printDocumentFooter(out, sRDF);
592: }
593: }
Webmaster