Source code for /engineering/autohit-1998/creator/compiler/XmlCompiler.javaOriginal file XmlCompiler.java
   1 /**
   2  * .
   3  * Copyright � 1999 Erich P G.
   4  *
   5  */
   6  
   7 package creator.compiler;
   8 
   9 import java.util.Vector;
  10 import java.io.InputStream;
  11 import java.io.File;
  12 import java.io.InputStreamReader;
  13 import java.io.FileInputStream;
  14 import java.io.EOFException;
  15 import org.xml.sax.InputSource;
  16 import com.sun.xml.parser.Parser;
  17 import com.sun.xml.parser.ValidatingParser;
  18 import com.sun.xml.tree.XmlDocument;
  19 import com.sun.xml.tree.XmlDocumentBuilder;
  20 import org.xml.sax.ErrorHandler; 
  21 
  22 
  23 /**
  24  * This is the a base XML compiler.  It must be extended by a specific compiler.  
  25  * Users of an extended class will call the compile() method in this class, which
  26  * will first parse the XML then call the abstract method build().  An extended
  27  * class must override the build() method and use to to compile from the 
  28  * xml document tree.
  29  *
  30  * This will load/cache the DTD by providing a new Resolver that will 
  31  * return a string reader to the cached DTD.
  32  *
  33  * WARNING!!!  For the compiler to work, the FIRST element of the java
  34  * CLASSPATH <b>must</b> be the root for the autohit installation.  The compiler
  35  * needs to find the XML DTD files in the "./lib" directory.
  36  *
  37  *
  38  * @author Erich P. Gatejen
  39  * @version 1.0
  40  * <i>Version History</i>
  41  * <code>EPG - Initial - 12Jan99</code> 
  42  * 
  43  */
  44 public abstract class XmlCompiler {
  45 	
  46 	// --- FINAL FIELDS ------------------------------------------------------	
  47 	private final static String dtdLocation = "/lib/";
  48 	private final static int    BUFFER_SIZE = 1024;
  49 
  50 	// --- FIELDS ------------------------------------------------------------
  51 
  52     /**
  53      *  Handles parse/compile errors and warnings.  Also serves as the ErrorHandler
  54      *  for the XML parser.
  55      *
  56      *  A new one will be/must be created for each compile.
  57      *
  58      *  @see creator.compiler.XmlParseErrorHandler
  59      */      	
  60     public XmlParseErrorHandler     err;
  61 
  62     /**
  63      *  The DTD to use when parsing the source text.
  64      */      	
  65     private String                  myDTD;
  66     
  67     /**
  68      *  The DTD to use when parsing the source text.
  69      */      	
  70     private XmlCompilerResolver     myResolver;
  71     
  72     /**
  73      *  The XML builder.
  74      */    
  75   	private XmlDocumentBuilder	    builder;
  76 	
  77     /**
  78      *  The XML parser.
  79      */    
  80   	protected Parser		        parser;    
  81     
  82 
  83 	// --- PUBLIC METHODS ----------------------------------------------------	
  84 
  85     /**
  86      *  Constructor.  You must use this and NOT the default.  
  87      *  It will make sure that the DTD for the SimLanguage is available.
  88      *
  89      *  If you use the defaulty constructor, the compiler will not know
  90      *  which DTD to use.
  91      *
  92      *  @param dtdURI URI of the DTD used in the !DOCTYPE * SYSTEM clause in the
  93      *                  compile targets.
  94      *  @throws Exception any exception invalidates the compiler.
  95      */
  96     public XmlCompiler(String  dtdURI) throws Exception {
  97 
  98         // Try to find the file
  99         String raw      = System.getProperty("java.class.path");
 100         
 101         String scrubbed      = raw.substring(0, raw.indexOf(";"));
 102         String scrubbedURI   = dtdURI.substring(dtdURI.indexOf(":") + 1);
 103         String dtdPath = new String(scrubbed + dtdLocation + scrubbedURI);
 104         
 105         // See if we can open and read it.  Allow any exceptions to be
 106         // thrown beyond this constructor.
 107         File              dtdFile = new File(dtdPath);
 108         InputStreamReader inFile  = new InputStreamReader( new FileInputStream(dtdFile) );
 109         StringBuffer      tempDTD = new StringBuffer();       
 110         
 111         try {
 112             char[]  buf = new char[BUFFER_SIZE];
 113             int     len;
 114             
 115             len = inFile.read(buf, 0, BUFFER_SIZE);
 116             while (len > 0) {
 117                 tempDTD.append(buf, 0, len);
 118                 len = inFile.read(buf, 0, BUFFER_SIZE);
 119             }
 120         
 121         } catch (EOFException e) {
 122             // Dont do anything.  this is A-OK.  For some odd reason, java.io
 123             // will sometimes throw an EOF instead of just returning a -1.
 124         } catch (Exception e) {
 125             throw(e);
 126         }
 127         
 128         // Set up a resolver from which the XML parser can get our DTD
 129         myDTD = tempDTD.toString();   
 130         
 131         myResolver = new XmlCompilerResolver(dtdURI, myDTD);
 132         
 133         // Prepare the XML document builder and parser
 134 	    builder = new XmlDocumentBuilder();
 135         parser = new ValidatingParser();              
 136 	    parser.setDocumentHandler(builder);
 137         parser.setEntityResolver(myResolver);
 138     }    
 139 
 140     /**
 141      *  Compile a stream into a new Sim object.  It will abort on a major error
 142      *  and return a null instead of a Sim instance.  Any compile errors or
 143      *  warnings can be found in the errors field.
 144      *
 145      *  @param is An input stream to the text that is to be compiled.
 146      *  @return a reference to the target object.
 147      *
 148      *  @see autohit.Sim
 149      */
 150     public Object compile(InputStream  is) {
 151         
 152         XmlDocument     parsedXML;
 153 
 154         Object  objectCode  = null;
 155 
 156         // Any exception aborts the compile
 157         try {
 158 
 159             // Start fresh
 160             err = new XmlParseErrorHandler();
 161             parser.setErrorHandler(err);
 162         
 163             // Drive the parser and build the document tree.
 164     	    parser.parse(new InputSource(is));   
 165             
 166             parsedXML = builder.getDocument();
 167             
 168 // DEBUG
 169 //parsedXML.write (System.out);             
 170             
 171             objectCode = build(parsedXML);
 172            
 173             
 174         } catch (Exception e) {
 175             objectCode = null; // leave the objectCode as null;
 176         }
 177        
 178         return objectCode;       
 179     }    
 180 
 181     /**
 182      *  Abstract build method.  Override with a method that builds the object code
 183      *  from the XML parse tree.
 184      *
 185      *  @param xd   A parsed XML document.
 186      *  
 187      *  @return Object reference to the object code.
 188      */
 189      public abstract Object build(XmlDocument  xd);
 190 
 191 
 192 	// --- PRIVATE METHODS ---------------------------------------------------	
 193 
 194 
 195 
 196 	// --- INTERNAL CLASSES ---------------------------------------------------	
 197 
 198 }