1 /* 2 * Copyright (c) 2007, 2016, 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 * $Id: TemplatesImpl.java,v 1.8 2007/03/26 20:12:27 spericas Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.trax; 25 26 import com.sun.org.apache.xalan.internal.XalanConstants; 27 import com.sun.org.apache.xalan.internal.utils.ObjectFactory; 28 import com.sun.org.apache.xalan.internal.utils.SecuritySupport; 29 import com.sun.org.apache.xalan.internal.xsltc.DOM; 30 import com.sun.org.apache.xalan.internal.xsltc.Translet; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 33 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 34 import java.io.IOException; 35 import java.io.UncheckedIOException; 36 import java.io.NotSerializableException; 37 import java.io.ObjectInputStream; 38 import java.io.ObjectOutputStream; 39 import java.io.ObjectStreamField; 40 import java.io.Serializable; 41 import java.lang.module.Configuration; 42 import java.lang.module.ModuleDescriptor; 43 import java.lang.module.ModuleFinder; 44 import java.lang.module.ModuleReference; 45 import java.lang.reflect.Layer; 46 import java.lang.reflect.Module; 47 import java.security.AccessController; 48 import java.security.PrivilegedAction; 49 import java.util.Arrays; 50 import java.util.HashMap; 51 import java.util.Map; 52 import java.util.Optional; 53 import java.util.Properties; 54 import java.util.Set; 55 import javax.xml.XMLConstants; 56 import javax.xml.transform.Templates; 57 import javax.xml.transform.Transformer; 58 import javax.xml.transform.TransformerConfigurationException; 59 import javax.xml.transform.URIResolver; 60 61 import jdk.internal.module.Modules; 62 63 /** 64 * @author Morten Jorgensen 65 * @author G. Todd Millerj 66 * @author Jochen Cordes <Jochen.Cordes@t-online.de> 67 * @author Santiago Pericas-Geertsen 68 */ 69 public final class TemplatesImpl implements Templates, Serializable { 70 static final long serialVersionUID = 673094361519270707L; 71 public final static String DESERIALIZE_TRANSLET = "jdk.xml.enableTemplatesImplDeserialization"; 72 73 /** 74 * Name of the superclass of all translets. This is needed to 75 * determine which, among all classes comprising a translet, 76 * is the main one. 77 */ 78 private static String ABSTRACT_TRANSLET 79 = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; 80 81 /** 82 * Name of the main class or default name if unknown. 83 */ 84 private String _name = null; 85 86 /** 87 * Contains the actual class definition for the translet class and 88 * any auxiliary classes. 89 */ 90 private byte[][] _bytecodes = null; 91 92 /** 93 * Contains the translet class definition(s). These are created when 94 * this Templates is created or when it is read back from disk. 95 */ 96 private Class[] _class = null; 97 98 /** 99 * The index of the main translet class in the arrays _class[] and 100 * _bytecodes. 101 */ 102 private int _transletIndex = -1; 103 104 /** 105 * Contains the list of auxiliary class definitions. 106 */ 107 private transient Map<String, Class<?>> _auxClasses = null; 108 109 /** 110 * Output properties of this translet. 111 */ 112 private Properties _outputProperties; 113 114 /** 115 * Number of spaces to add for output indentation. 116 */ 117 private int _indentNumber; 118 119 /** 120 * This URIResolver is passed to all Transformers. 121 * Declaring it transient to fix bug 22438 122 */ 123 private transient URIResolver _uriResolver = null; 124 125 /** 126 * Cache the DTM for the stylesheet in a thread local variable, 127 * which is used by the document('') function. 128 * Use ThreadLocal because a DTM cannot be shared between 129 * multiple threads. 130 * Declaring it transient to fix bug 22438 131 */ 132 private transient ThreadLocal _sdom = new ThreadLocal(); 133 134 /** 135 * A reference to the transformer factory that this templates 136 * object belongs to. 137 */ 138 private transient TransformerFactoryImpl _tfactory = null; 139 140 /** 141 * A flag to determine whether the Service Mechanism is used 142 */ 143 private transient boolean _useServicesMechanism; 144 145 /** 146 * protocols allowed for external references set by the stylesheet processing instruction, Import and Include element. 147 */ 148 private transient String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT; 149 150 /** 151 * @serialField _name String The Name of the main class 152 * @serialField _bytecodes byte[][] Class definition 153 * @serialField _class Class[] The translet class definition(s). 154 * @serialField _transletIndex int The index of the main translet class 155 * @serialField _outputProperties Properties Output properties of this translet. 156 * @serialField _indentNumber int Number of spaces to add for output indentation. 157 */ 158 private static final ObjectStreamField[] serialPersistentFields = 159 new ObjectStreamField[] { 160 new ObjectStreamField("_name", String.class), 161 new ObjectStreamField("_bytecodes", byte[][].class), 162 new ObjectStreamField("_class", Class[].class), 163 new ObjectStreamField("_transletIndex", int.class), 164 new ObjectStreamField("_outputProperties", Properties.class), 165 new ObjectStreamField("_indentNumber", int.class), 166 }; 167 168 static final class TransletClassLoader extends ClassLoader { 169 private final Map<String,Class> _loadedExternalExtensionFunctions; 170 171 TransletClassLoader(ClassLoader parent) { 172 super(parent); 173 _loadedExternalExtensionFunctions = null; 174 } 175 176 TransletClassLoader(ClassLoader parent,Map<String, Class> mapEF) { 177 super(parent); 178 _loadedExternalExtensionFunctions = mapEF; 179 } 180 181 public Class<?> loadClass(String name) throws ClassNotFoundException { 182 Class<?> ret = null; 183 // The _loadedExternalExtensionFunctions will be empty when the 184 // SecurityManager is not set and the FSP is turned off 185 if (_loadedExternalExtensionFunctions != null) { 186 ret = _loadedExternalExtensionFunctions.get(name); 187 } 188 if (ret == null) { 189 ret = super.loadClass(name); 190 } 191 return ret; 192 } 193 194 /** 195 * Access to final protected superclass member from outer class. 196 */ 197 Class defineClass(final byte[] b) { 198 return defineClass(null, b, 0, b.length); 199 } 200 } 201 202 203 /** 204 * Create an XSLTC template object from the bytecodes. 205 * The bytecodes for the translet and auxiliary classes, plus the name of 206 * the main translet class, must be supplied. 207 */ 208 protected TemplatesImpl(byte[][] bytecodes, String transletName, 209 Properties outputProperties, int indentNumber, 210 TransformerFactoryImpl tfactory) 211 { 212 _bytecodes = bytecodes; 213 init(transletName, outputProperties, indentNumber, tfactory); 214 } 215 216 /** 217 * Create an XSLTC template object from the translet class definition(s). 218 */ 219 protected TemplatesImpl(Class[] transletClasses, String transletName, 220 Properties outputProperties, int indentNumber, 221 TransformerFactoryImpl tfactory) 222 { 223 _class = transletClasses; 224 _transletIndex = 0; 225 init(transletName, outputProperties, indentNumber, tfactory); 226 } 227 228 private void init(String transletName, 229 Properties outputProperties, int indentNumber, 230 TransformerFactoryImpl tfactory) { 231 _name = transletName; 232 _outputProperties = outputProperties; 233 _indentNumber = indentNumber; 234 _tfactory = tfactory; 235 _useServicesMechanism = tfactory.useServicesMechnism(); 236 _accessExternalStylesheet = (String) tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET); 237 } 238 /** 239 * Need for de-serialization, see readObject(). 240 */ 241 public TemplatesImpl() { } 242 243 /** 244 * Overrides the default readObject implementation since we decided 245 * it would be cleaner not to serialize the entire tranformer 246 * factory. [ ref bugzilla 12317 ] 247 * We need to check if the user defined class for URIResolver also 248 * implemented Serializable 249 * if yes then we need to deserialize the URIResolver 250 * Fix for bugzilla bug 22438 251 */ 252 @SuppressWarnings("unchecked") 253 private void readObject(ObjectInputStream is) 254 throws IOException, ClassNotFoundException 255 { 256 SecurityManager security = System.getSecurityManager(); 257 if (security != null){ 258 String temp = SecuritySupport.getSystemProperty(DESERIALIZE_TRANSLET); 259 if (temp == null || !(temp.length()==0 || temp.equalsIgnoreCase("true"))) { 260 ErrorMsg err = new ErrorMsg(ErrorMsg.DESERIALIZE_TRANSLET_ERR); 261 throw new UnsupportedOperationException(err.toString()); 262 } 263 } 264 265 // We have to read serialized fields first. 266 ObjectInputStream.GetField gf = is.readFields(); 267 _name = (String)gf.get("_name", null); 268 _bytecodes = (byte[][])gf.get("_bytecodes", null); 269 _class = (Class[])gf.get("_class", null); 270 _transletIndex = gf.get("_transletIndex", -1); 271 272 _outputProperties = (Properties)gf.get("_outputProperties", null); 273 _indentNumber = gf.get("_indentNumber", 0); 274 275 if (is.readBoolean()) { 276 _uriResolver = (URIResolver) is.readObject(); 277 } 278 279 _tfactory = new TransformerFactoryImpl(); 280 } 281 282 283 /** 284 * This is to fix bugzilla bug 22438 285 * If the user defined class implements URIResolver and Serializable 286 * then we want it to get serialized 287 */ 288 private void writeObject(ObjectOutputStream os) 289 throws IOException, ClassNotFoundException { 290 if (_auxClasses != null) { 291 //throw with the same message as when Hashtable was used for compatibility. 292 throw new NotSerializableException( 293 "com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable"); 294 } 295 296 // Write serialized fields 297 ObjectOutputStream.PutField pf = os.putFields(); 298 pf.put("_name", _name); 299 pf.put("_bytecodes", _bytecodes); 300 pf.put("_class", _class); 301 pf.put("_transletIndex", _transletIndex); 302 pf.put("_outputProperties", _outputProperties); 303 pf.put("_indentNumber", _indentNumber); 304 os.writeFields(); 305 306 if (_uriResolver instanceof Serializable) { 307 os.writeBoolean(true); 308 os.writeObject((Serializable) _uriResolver); 309 } 310 else { 311 os.writeBoolean(false); 312 } 313 } 314 315 /** 316 * Return the state of the services mechanism feature. 317 */ 318 public boolean useServicesMechnism() { 319 return _useServicesMechanism; 320 } 321 322 /** 323 * Store URIResolver needed for Transformers. 324 */ 325 public synchronized void setURIResolver(URIResolver resolver) { 326 _uriResolver = resolver; 327 } 328 329 /** 330 * The TransformerFactory must pass us the translet bytecodes using this 331 * method before we can create any translet instances 332 * 333 * Note: This method is private for security reasons. See 334 * CR 6537898. When merging with Apache, we must ensure 335 * that the privateness of this method is maintained (that 336 * is why it wasn't removed). 337 */ 338 private synchronized void setTransletBytecodes(byte[][] bytecodes) { 339 _bytecodes = bytecodes; 340 } 341 342 /** 343 * Returns the translet bytecodes stored in this template 344 * 345 * Note: This method is private for security reasons. See 346 * CR 6537898. When merging with Apache, we must ensure 347 * that the privateness of this method is maintained (that 348 * is why it wasn't removed). 349 */ 350 private synchronized byte[][] getTransletBytecodes() { 351 return _bytecodes; 352 } 353 354 /** 355 * Returns the translet bytecodes stored in this template 356 * 357 * Note: This method is private for security reasons. See 358 * CR 6537898. When merging with Apache, we must ensure 359 * that the privateness of this method is maintained (that 360 * is why it wasn't removed). 361 */ 362 private synchronized Class[] getTransletClasses() { 363 try { 364 if (_class == null) defineTransletClasses(); 365 } 366 catch (TransformerConfigurationException e) { 367 // Falls through 368 } 369 return _class; 370 } 371 372 /** 373 * Returns the index of the main class in array of bytecodes 374 */ 375 public synchronized int getTransletIndex() { 376 try { 377 if (_class == null) defineTransletClasses(); 378 } 379 catch (TransformerConfigurationException e) { 380 // Falls through 381 } 382 return _transletIndex; 383 } 384 385 /** 386 * The TransformerFactory should call this method to set the translet name 387 */ 388 protected synchronized void setTransletName(String name) { 389 _name = name; 390 } 391 392 /** 393 * Returns the name of the main translet class stored in this template 394 */ 395 protected synchronized String getTransletName() { 396 return _name; 397 } 398 399 400 /** 401 * Creates a module layer with one module that is defined to the given class 402 * loader. 403 */ 404 private Module createModule(ModuleDescriptor descriptor, ClassLoader loader) { 405 String mn = descriptor.name(); 406 407 ModuleReference mref = new ModuleReference(descriptor, null, () -> { 408 IOException ioe = new IOException("<dynamic module>"); 409 throw new UncheckedIOException(ioe); 410 }); 411 412 ModuleFinder finder = new ModuleFinder() { 413 @Override 414 public Optional<ModuleReference> find(String name) { 415 if (name.equals(mn)) { 416 return Optional.of(mref); 417 } else { 418 return Optional.empty(); 419 } 420 } 421 @Override 422 public Set<ModuleReference> findAll() { 423 return Set.of(mref); 424 } 425 }; 426 427 Layer bootLayer = Layer.boot(); 428 429 Configuration cf = bootLayer.configuration() 430 .resolveRequires(finder, ModuleFinder.of(), Set.of(mn)); 431 432 PrivilegedAction<Layer> pa = () -> bootLayer.defineModules(cf, name -> loader); 433 Layer layer = AccessController.doPrivileged(pa); 434 435 Module m = layer.findModule(mn).get(); 436 assert m.getLayer() == layer; 437 438 return m; 439 } 440 441 /** 442 * Defines the translet class and auxiliary classes. 443 * Returns a reference to the Class object that defines the main class 444 */ 445 private void defineTransletClasses() 446 throws TransformerConfigurationException { 447 448 if (_bytecodes == null) { 449 ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); 450 throw new TransformerConfigurationException(err.toString()); 451 } 452 453 TransletClassLoader loader = (TransletClassLoader) 454 AccessController.doPrivileged(new PrivilegedAction() { 455 public Object run() { 456 return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()); 457 } 458 }); 459 460 try { 461 final int classCount = _bytecodes.length; 462 _class = new Class[classCount]; 463 464 if (classCount > 1) { 465 _auxClasses = new HashMap<>(); 466 } 467 468 // create a module for the translet 469 470 String mn = "jdk.translet"; 471 472 String pn = _tfactory.getPackageName(); 473 assert pn != null && pn.length() > 0; 474 475 ModuleDescriptor descriptor 476 = new ModuleDescriptor.Builder(mn) 477 .requires("java.xml") 478 .exports(pn) 479 .build(); 480 481 Module m = createModule(descriptor, loader); 482 483 // the module needs access to runtime classes 484 Module thisModule = TemplatesImpl.class.getModule(); 485 Arrays.asList(Constants.PKGS_USED_BY_TRANSLET_CLASSES).forEach(p -> { 486 thisModule.addExports(p, m); 487 }); 488 489 // For now, the module reads all unnnamed modules. This will be changed once 490 // the XSLT compiler is updated to generate code to invoke addReads. 491 Modules.addReadsAllUnnamed(m); 492 493 // java.xml needs to instanitate the translet class 494 thisModule.addReads(m); 495 496 for (int i = 0; i < classCount; i++) { 497 _class[i] = loader.defineClass(_bytecodes[i]); 498 final Class superClass = _class[i].getSuperclass(); 499 500 // Check if this is the main class 501 if (superClass.getName().equals(ABSTRACT_TRANSLET)) { 502 _transletIndex = i; 503 } 504 else { 505 _auxClasses.put(_class[i].getName(), _class[i]); 506 } 507 } 508 509 if (_transletIndex < 0) { 510 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); 511 throw new TransformerConfigurationException(err.toString()); 512 } 513 } 514 catch (ClassFormatError e) { 515 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name); 516 throw new TransformerConfigurationException(err.toString()); 517 } 518 catch (LinkageError e) { 519 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); 520 throw new TransformerConfigurationException(err.toString(), e); 521 } 522 } 523 524 /** 525 * This method generates an instance of the translet class that is 526 * wrapped inside this Template. The translet instance will later 527 * be wrapped inside a Transformer object. 528 */ 529 private Translet getTransletInstance() 530 throws TransformerConfigurationException { 531 try { 532 if (_name == null) return null; 533 534 if (_class == null) defineTransletClasses(); 535 536 // The translet needs to keep a reference to all its auxiliary 537 // class to prevent the GC from collecting them 538 AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance(); 539 translet.postInitialization(); 540 translet.setTemplates(this); 541 translet.setServicesMechnism(_useServicesMechanism); 542 translet.setAllowedProtocols(_accessExternalStylesheet); 543 if (_auxClasses != null) { 544 translet.setAuxiliaryClasses(_auxClasses); 545 } 546 547 return translet; 548 } 549 catch (InstantiationException e) { 550 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); 551 throw new TransformerConfigurationException(err.toString()); 552 } 553 catch (IllegalAccessException e) { 554 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); 555 throw new TransformerConfigurationException(err.toString()); 556 } 557 } 558 559 /** 560 * Implements JAXP's Templates.newTransformer() 561 * 562 * @throws TransformerConfigurationException 563 */ 564 public synchronized Transformer newTransformer() 565 throws TransformerConfigurationException 566 { 567 TransformerImpl transformer; 568 569 transformer = new TransformerImpl(getTransletInstance(), _outputProperties, 570 _indentNumber, _tfactory); 571 572 if (_uriResolver != null) { 573 transformer.setURIResolver(_uriResolver); 574 } 575 576 if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) { 577 transformer.setSecureProcessing(true); 578 } 579 return transformer; 580 } 581 582 /** 583 * Implements JAXP's Templates.getOutputProperties(). We need to 584 * instanciate a translet to get the output settings, so 585 * we might as well just instanciate a Transformer and use its 586 * implementation of this method. 587 */ 588 public synchronized Properties getOutputProperties() { 589 try { 590 return newTransformer().getOutputProperties(); 591 } 592 catch (TransformerConfigurationException e) { 593 return null; 594 } 595 } 596 597 /** 598 * Return the thread local copy of the stylesheet DOM. 599 */ 600 public DOM getStylesheetDOM() { 601 return (DOM)_sdom.get(); 602 } 603 604 /** 605 * Set the thread local copy of the stylesheet DOM. 606 */ 607 public void setStylesheetDOM(DOM sdom) { 608 _sdom.set(sdom); 609 } 610 }