1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2001-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: TemplatesHandlerImpl.java,v 1.2.4.1 2005/09/06 12:09:03 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.trax;
  25 
  26 import javax.xml.XMLConstants;
  27 import javax.xml.transform.Source;
  28 import javax.xml.transform.Templates;
  29 import javax.xml.transform.TransformerException;
  30 import javax.xml.transform.URIResolver;
  31 import javax.xml.transform.sax.TemplatesHandler;
  32 
  33 import com.sun.org.apache.xalan.internal.xsltc.compiler.CompilerException;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.Parser;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.SourceLoader;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.Stylesheet;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.SyntaxTreeNode;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC;
  39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  40 
  41 import org.xml.sax.ContentHandler;
  42 import org.xml.sax.InputSource;
  43 import org.xml.sax.Locator;
  44 import org.xml.sax.SAXException;
  45 import org.xml.sax.Attributes;
  46 
  47 import java.util.Vector;
  48 
  49 /**
  50  * Implementation of a JAXP1.1 TemplatesHandler
  51  * @author Morten Jorgensen
  52  * @author Santiago Pericas-Geertsen
  53  */
  54 public class TemplatesHandlerImpl
  55     implements ContentHandler, TemplatesHandler, SourceLoader
  56 {
  57     /**
  58      * System ID for this stylesheet.
  59      */
  60     private String _systemId;
  61 
  62     /**
  63      * Number of spaces to add for output indentation.
  64      */
  65     private int _indentNumber;
  66 
  67     /**
  68      * This URIResolver is passed to all Transformers.
  69      */
  70     private URIResolver _uriResolver = null;
  71 
  72     /**
  73      * A reference to the transformer factory that this templates
  74      * object belongs to.
  75      */
  76     private TransformerFactoryImpl _tfactory = null;
  77 
  78     /**
  79      * A reference to XSLTC's parser object.
  80      */
  81     private Parser _parser = null;
  82 
  83     /**
  84      * The created Templates object.
  85      */
  86     private TemplatesImpl _templates = null;
  87 
  88     /**
  89      * Default constructor
  90      */
  91     protected TemplatesHandlerImpl(int indentNumber,
  92         TransformerFactoryImpl tfactory)
  93     {
  94         _indentNumber = indentNumber;
  95         _tfactory = tfactory;
  96 
  97         // Instantiate XSLTC and get reference to parser object
  98         XSLTC xsltc = new XSLTC(tfactory.useServicesMechnism());
  99         if (tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING))
 100             xsltc.setSecureProcessing(true);
 101 
 102         if ("true".equals(tfactory.getAttribute(TransformerFactoryImpl.ENABLE_INLINING)))
 103             xsltc.setTemplateInlining(true);
 104         else
 105             xsltc.setTemplateInlining(false);
 106 
 107         _parser = xsltc.getParser();
 108     }
 109 
 110     /**
 111      * Implements javax.xml.transform.sax.TemplatesHandler.getSystemId()
 112      * Get the base ID (URI or system ID) from where relative URLs will be
 113      * resolved.
 114      * @return The systemID that was set with setSystemId(String id)
 115      */
 116     public String getSystemId() {
 117         return _systemId;
 118     }
 119 
 120     /**
 121      * Implements javax.xml.transform.sax.TemplatesHandler.setSystemId()
 122      * Get the base ID (URI or system ID) from where relative URLs will be
 123      * resolved.
 124      * @param id Base URI for this stylesheet
 125      */
 126     public void setSystemId(String id) {
 127         _systemId = id;
 128     }
 129 
 130     /**
 131      * Store URIResolver needed for Transformers.
 132      */
 133     public void setURIResolver(URIResolver resolver) {
 134         _uriResolver = resolver;
 135     }
 136 
 137     /**
 138      * Implements javax.xml.transform.sax.TemplatesHandler.getTemplates()
 139      * When a TemplatesHandler object is used as a ContentHandler or
 140      * DocumentHandler for the parsing of transformation instructions, it
 141      * creates a Templates object, which the caller can get once the SAX
 142      * events have been completed.
 143      * @return The Templates object that was created during the SAX event
 144      *         process, or null if no Templates object has been created.
 145      */
 146     public Templates getTemplates() {
 147         return _templates;
 148     }
 149 
 150     /**
 151      * This method implements XSLTC's SourceLoader interface. It is used to
 152      * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes.
 153      *
 154      * @param href The URI of the document to load
 155      * @param context The URI of the currently loaded document
 156      * @param xsltc The compiler that resuests the document
 157      * @return An InputSource with the loaded document
 158      */
 159     public InputSource loadSource(String href, String context, XSLTC xsltc) {
 160         try {
 161             // A _uriResolver must be set if this method is called
 162             final Source source = _uriResolver.resolve(href, context);
 163             if (source != null) {
 164                 return Util.getInputSource(xsltc, source);
 165             }
 166         }
 167         catch (TransformerException e) {
 168             // Falls through
 169         }
 170         return null;
 171     }
 172 
 173     // -- ContentHandler --------------------------------------------------
 174 
 175     /**
 176      * Re-initialize parser and forward SAX2 event.
 177      */
 178     public void startDocument() {
 179         XSLTC xsltc = _parser.getXSLTC();
 180         xsltc.init();   // calls _parser.init()
 181         xsltc.setOutputType(XSLTC.BYTEARRAY_OUTPUT);
 182         _parser.startDocument();
 183     }
 184 
 185     /**
 186      * Just forward SAX2 event to parser object.
 187      */
 188     public void endDocument() throws SAXException {
 189         _parser.endDocument();
 190 
 191         // create the templates
 192         try {
 193             XSLTC xsltc = _parser.getXSLTC();
 194 
 195             // Set the translet class name if not already set
 196             String transletName;
 197             if (_systemId != null) {
 198                 transletName = Util.baseName(_systemId);
 199             }
 200             else {
 201                 transletName = (String)_tfactory.getAttribute("translet-name");
 202             }
 203             xsltc.setClassName(transletName);
 204 
 205             // Get java-legal class name from XSLTC module
 206             transletName = xsltc.getClassName();
 207 
 208             Stylesheet stylesheet = null;
 209             SyntaxTreeNode root = _parser.getDocumentRoot();
 210 
 211             // Compile the translet - this is where the work is done!
 212             if (!_parser.errorsFound() && root != null) {
 213                 // Create a Stylesheet element from the root node
 214                 stylesheet = _parser.makeStylesheet(root);
 215                 stylesheet.setSystemId(_systemId);
 216                 stylesheet.setParentStylesheet(null);
 217 
 218                 if (xsltc.getTemplateInlining())
 219                    stylesheet.setTemplateInlining(true);
 220                 else
 221                    stylesheet.setTemplateInlining(false);
 222 
 223                 // Set a document loader (for xsl:include/import) if defined
 224                 if (_uriResolver != null) {
 225                     stylesheet.setSourceLoader(this);
 226                 }
 227 
 228                 _parser.setCurrentStylesheet(stylesheet);
 229 
 230                 // Set it as top-level in the XSLTC object
 231                 xsltc.setStylesheet(stylesheet);
 232 
 233                 // Create AST under the Stylesheet element
 234                 _parser.createAST(stylesheet);
 235             }
 236 
 237             // Generate the bytecodes and output the translet class(es)
 238             if (!_parser.errorsFound() && stylesheet != null) {
 239                 stylesheet.setMultiDocument(xsltc.isMultiDocument());
 240                 stylesheet.setHasIdCall(xsltc.hasIdCall());
 241 
 242                 // Class synchronization is needed for BCEL
 243                 synchronized (xsltc.getClass()) {
 244                     stylesheet.translate();
 245                 }
 246             }
 247 
 248             if (!_parser.errorsFound()) {
 249                 // Check that the transformation went well before returning
 250                 final byte[][] bytecodes = xsltc.getBytecodes();
 251                 if (bytecodes != null) {
 252                     _templates =
 253                     new TemplatesImpl(xsltc.getBytecodes(), transletName,
 254                         _parser.getOutputProperties(), _indentNumber, _tfactory);
 255 
 256                     // Set URIResolver on templates object
 257                     if (_uriResolver != null) {
 258                         _templates.setURIResolver(_uriResolver);
 259                     }
 260                 }
 261             }
 262             else {
 263                 StringBuffer errorMessage = new StringBuffer();
 264                 Vector errors = _parser.getErrors();
 265                 final int count = errors.size();
 266                 for (int i = 0; i < count; i++) {
 267                     if (errorMessage.length() > 0)
 268                         errorMessage.append('\n');
 269                     errorMessage.append(errors.elementAt(i).toString());
 270                 }
 271                 throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, new TransformerException(errorMessage.toString()));
 272             }
 273         }
 274         catch (CompilerException e) {
 275             throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, e);
 276         }
 277     }
 278 
 279     /**
 280      * Just forward SAX2 event to parser object.
 281      */
 282     public void startPrefixMapping(String prefix, String uri) {
 283         _parser.startPrefixMapping(prefix, uri);
 284     }
 285 
 286     /**
 287      * Just forward SAX2 event to parser object.
 288      */
 289     public void endPrefixMapping(String prefix) {
 290         _parser.endPrefixMapping(prefix);
 291     }
 292 
 293     /**
 294      * Just forward SAX2 event to parser object.
 295      */
 296     public void startElement(String uri, String localname, String qname,
 297         Attributes attributes) throws SAXException
 298     {
 299         _parser.startElement(uri, localname, qname, attributes);
 300     }
 301 
 302     /**
 303      * Just forward SAX2 event to parser object.
 304      */
 305     public void endElement(String uri, String localname, String qname) {
 306         _parser.endElement(uri, localname, qname);
 307     }
 308 
 309     /**
 310      * Just forward SAX2 event to parser object.
 311      */
 312     public void characters(char[] ch, int start, int length) {
 313         _parser.characters(ch, start, length);
 314     }
 315 
 316     /**
 317      * Just forward SAX2 event to parser object.
 318      */
 319     public void processingInstruction(String name, String value) {
 320         _parser.processingInstruction(name, value);
 321     }
 322 
 323     /**
 324      * Just forward SAX2 event to parser object.
 325      */
 326     public void ignorableWhitespace(char[] ch, int start, int length) {
 327         _parser.ignorableWhitespace(ch, start, length);
 328     }
 329 
 330     /**
 331      * Just forward SAX2 event to parser object.
 332      */
 333     public void skippedEntity(String name) {
 334         _parser.skippedEntity(name);
 335     }
 336 
 337     /**
 338      * Set internal system Id and forward SAX2 event to parser object.
 339      */
 340     public void setDocumentLocator(Locator locator) {
 341         setSystemId(locator.getSystemId());
 342         _parser.setDocumentLocator(locator);
 343     }
 344 }