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 }