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 }