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 import com.sun.org.apache.xalan.internal.XalanConstants;
  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(), tfactory.getFeatureManager());
  99         if (tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING))
 100             xsltc.setSecureProcessing(true);
 101 
 102         xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
 103                 (String)tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET));
 104         xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD,
 105                 (String)tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD));
 106         xsltc.setProperty(XalanConstants.SECURITY_MANAGER,
 107                 tfactory.getAttribute(XalanConstants.SECURITY_MANAGER));
 108 
 109 
 110         if ("true".equals(tfactory.getAttribute(TransformerFactoryImpl.ENABLE_INLINING)))
 111             xsltc.setTemplateInlining(true);
 112         else
 113             xsltc.setTemplateInlining(false);
 114 
 115         _parser = xsltc.getParser();
 116     }
 117 
 118     /**
 119      * Implements javax.xml.transform.sax.TemplatesHandler.getSystemId()
 120      * Get the base ID (URI or system ID) from where relative URLs will be
 121      * resolved.
 122      * @return The systemID that was set with setSystemId(String id)
 123      */
 124     public String getSystemId() {
 125         return _systemId;
 126     }
 127 
 128     /**
 129      * Implements javax.xml.transform.sax.TemplatesHandler.setSystemId()
 130      * Get the base ID (URI or system ID) from where relative URLs will be
 131      * resolved.
 132      * @param id Base URI for this stylesheet
 133      */
 134     public void setSystemId(String id) {
 135         _systemId = id;
 136     }
 137 
 138     /**
 139      * Store URIResolver needed for Transformers.
 140      */
 141     public void setURIResolver(URIResolver resolver) {
 142         _uriResolver = resolver;
 143     }
 144 
 145     /**
 146      * Implements javax.xml.transform.sax.TemplatesHandler.getTemplates()
 147      * When a TemplatesHandler object is used as a ContentHandler or
 148      * DocumentHandler for the parsing of transformation instructions, it
 149      * creates a Templates object, which the caller can get once the SAX
 150      * events have been completed.
 151      * @return The Templates object that was created during the SAX event
 152      *         process, or null if no Templates object has been created.
 153      */
 154     public Templates getTemplates() {
 155         return _templates;
 156     }
 157 
 158     /**
 159      * This method implements XSLTC's SourceLoader interface. It is used to
 160      * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes.
 161      *
 162      * @param href The URI of the document to load
 163      * @param context The URI of the currently loaded document
 164      * @param xsltc The compiler that resuests the document
 165      * @return An InputSource with the loaded document
 166      */
 167     public InputSource loadSource(String href, String context, XSLTC xsltc) {
 168         try {
 169             // A _uriResolver must be set if this method is called
 170             final Source source = _uriResolver.resolve(href, context);
 171             if (source != null) {
 172                 return Util.getInputSource(xsltc, source);
 173             }
 174         }
 175         catch (TransformerException e) {
 176             // Falls through
 177         }
 178         return null;
 179     }
 180 
 181     // -- ContentHandler --------------------------------------------------
 182 
 183     /**
 184      * Re-initialize parser and forward SAX2 event.
 185      */
 186     public void startDocument() {
 187         XSLTC xsltc = _parser.getXSLTC();
 188         xsltc.init();   // calls _parser.init()
 189         xsltc.setOutputType(XSLTC.BYTEARRAY_OUTPUT);
 190         _parser.startDocument();
 191     }
 192 
 193     /**
 194      * Just forward SAX2 event to parser object.
 195      */
 196     public void endDocument() throws SAXException {
 197         _parser.endDocument();
 198 
 199         // create the templates
 200         try {
 201             XSLTC xsltc = _parser.getXSLTC();
 202 
 203             // Set the translet class name if not already set
 204             String transletName;
 205             if (_systemId != null) {
 206                 transletName = Util.baseName(_systemId);
 207             }
 208             else {
 209                 transletName = (String)_tfactory.getAttribute("translet-name");
 210             }
 211             xsltc.setClassName(transletName);
 212 
 213             // Get java-legal class name from XSLTC module
 214             transletName = xsltc.getClassName();
 215 
 216             Stylesheet stylesheet = null;
 217             SyntaxTreeNode root = _parser.getDocumentRoot();
 218 
 219             // Compile the translet - this is where the work is done!
 220             if (!_parser.errorsFound() && root != null) {
 221                 // Create a Stylesheet element from the root node
 222                 stylesheet = _parser.makeStylesheet(root);
 223                 stylesheet.setSystemId(_systemId);
 224                 stylesheet.setParentStylesheet(null);
 225 
 226                 if (xsltc.getTemplateInlining())
 227                    stylesheet.setTemplateInlining(true);
 228                 else
 229                    stylesheet.setTemplateInlining(false);
 230 
 231                 // Set a document loader (for xsl:include/import) if defined
 232                 if (_uriResolver != null) {
 233                     stylesheet.setSourceLoader(this);
 234                 }
 235 
 236                 _parser.setCurrentStylesheet(stylesheet);
 237 
 238                 // Set it as top-level in the XSLTC object
 239                 xsltc.setStylesheet(stylesheet);
 240 
 241                 // Create AST under the Stylesheet element
 242                 _parser.createAST(stylesheet);
 243             }
 244 
 245             // Generate the bytecodes and output the translet class(es)
 246             if (!_parser.errorsFound() && stylesheet != null) {
 247                 stylesheet.setMultiDocument(xsltc.isMultiDocument());
 248                 stylesheet.setHasIdCall(xsltc.hasIdCall());
 249 
 250                 // Class synchronization is needed for BCEL
 251                 synchronized (xsltc.getClass()) {
 252                     stylesheet.translate();
 253                 }
 254             }
 255 
 256             if (!_parser.errorsFound()) {
 257                 // Check that the transformation went well before returning
 258                 final byte[][] bytecodes = xsltc.getBytecodes();
 259                 if (bytecodes != null) {
 260                     _templates =
 261                     new TemplatesImpl(xsltc.getBytecodes(), transletName,
 262                         _parser.getOutputProperties(), _indentNumber, _tfactory);
 263 
 264                     // Set URIResolver on templates object
 265                     if (_uriResolver != null) {
 266                         _templates.setURIResolver(_uriResolver);
 267                     }
 268                 }
 269             }
 270             else {
 271                 StringBuffer errorMessage = new StringBuffer();
 272                 Vector errors = _parser.getErrors();
 273                 final int count = errors.size();
 274                 for (int i = 0; i < count; i++) {
 275                     if (errorMessage.length() > 0)
 276                         errorMessage.append('\n');
 277                     errorMessage.append(errors.elementAt(i).toString());
 278                 }
 279                 throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, new TransformerException(errorMessage.toString()));
 280             }
 281         }
 282         catch (CompilerException e) {
 283             throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, e);
 284         }
 285     }
 286 
 287     /**
 288      * Just forward SAX2 event to parser object.
 289      */
 290     public void startPrefixMapping(String prefix, String uri) {
 291         _parser.startPrefixMapping(prefix, uri);
 292     }
 293 
 294     /**
 295      * Just forward SAX2 event to parser object.
 296      */
 297     public void endPrefixMapping(String prefix) {
 298         _parser.endPrefixMapping(prefix);
 299     }
 300 
 301     /**
 302      * Just forward SAX2 event to parser object.
 303      */
 304     public void startElement(String uri, String localname, String qname,
 305         Attributes attributes) throws SAXException
 306     {
 307         _parser.startElement(uri, localname, qname, attributes);
 308     }
 309 
 310     /**
 311      * Just forward SAX2 event to parser object.
 312      */
 313     public void endElement(String uri, String localname, String qname) {
 314         _parser.endElement(uri, localname, qname);
 315     }
 316 
 317     /**
 318      * Just forward SAX2 event to parser object.
 319      */
 320     public void characters(char[] ch, int start, int length) {
 321         _parser.characters(ch, start, length);
 322     }
 323 
 324     /**
 325      * Just forward SAX2 event to parser object.
 326      */
 327     public void processingInstruction(String name, String value) {
 328         _parser.processingInstruction(name, value);
 329     }
 330 
 331     /**
 332      * Just forward SAX2 event to parser object.
 333      */
 334     public void ignorableWhitespace(char[] ch, int start, int length) {
 335         _parser.ignorableWhitespace(ch, start, length);
 336     }
 337 
 338     /**
 339      * Just forward SAX2 event to parser object.
 340      */
 341     public void skippedEntity(String name) {
 342         _parser.skippedEntity(name);
 343     }
 344 
 345     /**
 346      * Set internal system Id and forward SAX2 event to parser object.
 347      */
 348     public void setDocumentLocator(Locator locator) {
 349         setSystemId(locator.getSystemId());
 350         _parser.setDocumentLocator(locator);
 351     }
 352 }