Annotation of java/classes/org/w3c/rdf/examples/ARPServlet.java, revision 1.61

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

Webmaster