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