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