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