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