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