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 }