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