rev 1063 : 8172974: [JAXP] XALAN: Wrong result when transforming namespace unaware StAX Input

   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.NotSerializableException;
  36 import java.io.ObjectInputStream;
  37 import java.io.ObjectOutputStream;
  38 import java.io.ObjectStreamField;
  39 import java.io.Serializable;
  40 import java.lang.module.Configuration;
  41 import java.lang.module.ModuleDescriptor;
  42 import java.lang.module.ModuleFinder;
  43 import java.lang.module.ModuleReference;
  44 import java.lang.module.ModuleReader;
  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             @Override
 408             public ModuleReader open() {
 409                 throw new UnsupportedOperationException();
 410             }
 411         };
 412 
 413         ModuleFinder finder = new ModuleFinder() {
 414             @Override
 415             public Optional<ModuleReference> find(String name) {
 416                 if (name.equals(mn)) {
 417                     return Optional.of(mref);
 418                 } else {
 419                     return Optional.empty();
 420                 }
 421             }
 422             @Override
 423             public Set<ModuleReference> findAll() {
 424                 return Set.of(mref);
 425             }
 426         };
 427 
 428         Layer bootLayer = Layer.boot();
 429 
 430         Configuration cf = bootLayer.configuration()
 431                 .resolveRequires(finder, ModuleFinder.of(), Set.of(mn));
 432 
 433         PrivilegedAction<Layer> pa = () -> bootLayer.defineModules(cf, name -> loader);
 434         Layer layer = AccessController.doPrivileged(pa);
 435 
 436         Module m = layer.findModule(mn).get();
 437         assert m.getLayer() == layer;
 438 
 439         return m;
 440     }
 441 
 442     /**
 443      * Defines the translet class and auxiliary classes.
 444      * Returns a reference to the Class object that defines the main class
 445      */
 446     private void defineTransletClasses()
 447         throws TransformerConfigurationException {
 448 
 449         if (_bytecodes == null) {
 450             ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
 451             throw new TransformerConfigurationException(err.toString());
 452         }
 453 
 454         TransletClassLoader loader = (TransletClassLoader)
 455             AccessController.doPrivileged(new PrivilegedAction() {
 456                 public Object run() {
 457                     return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
 458                 }
 459             });
 460 
 461         try {
 462             final int classCount = _bytecodes.length;
 463             _class = new Class[classCount];
 464 
 465             if (classCount > 1) {
 466                 _auxClasses = new HashMap<>();
 467             }
 468 
 469             // create a module for the translet
 470 
 471             String mn = "jdk.translet";
 472 
 473             String pn = _tfactory.getPackageName();
 474             assert pn != null && pn.length() > 0;
 475 
 476             ModuleDescriptor descriptor = ModuleDescriptor.module(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 
 486             Arrays.asList(Constants.PKGS_USED_BY_TRANSLET_CLASSES).forEach(p -> {
 487                 thisModule.addExports(p, m);
 488             });
 489 
 490             // java.xml needs to instanitate the translet class
 491             thisModule.addReads(m);
 492 
 493             for (int i = 0; i < classCount; i++) {
 494                 _class[i] = loader.defineClass(_bytecodes[i]);
 495                 final Class superClass = _class[i].getSuperclass();
 496 
 497                 // Check if this is the main class
 498                 if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
 499                     _transletIndex = i;
 500                 }
 501                 else {
 502                     _auxClasses.put(_class[i].getName(), _class[i]);
 503                 }
 504             }
 505 
 506             if (_transletIndex < 0) {
 507                 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
 508                 throw new TransformerConfigurationException(err.toString());
 509             }
 510         }
 511         catch (ClassFormatError e) {
 512             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
 513             throw new TransformerConfigurationException(err.toString(), e);
 514         }
 515         catch (LinkageError e) {
 516             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
 517             throw new TransformerConfigurationException(err.toString(), e);
 518         }
 519     }
 520 
 521     /**
 522      * This method generates an instance of the translet class that is
 523      * wrapped inside this Template. The translet instance will later
 524      * be wrapped inside a Transformer object.
 525      */
 526     private Translet getTransletInstance()
 527         throws TransformerConfigurationException {
 528         try {
 529             if (_name == null) return null;
 530 
 531             if (_class == null) defineTransletClasses();
 532 
 533             // The translet needs to keep a reference to all its auxiliary
 534             // class to prevent the GC from collecting them
 535             AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
 536             translet.postInitialization();
 537             translet.setTemplates(this);
 538             translet.setServicesMechnism(_useServicesMechanism);
 539             translet.setAllowedProtocols(_accessExternalStylesheet);
 540             if (_auxClasses != null) {
 541                 translet.setAuxiliaryClasses(_auxClasses);
 542             }
 543 
 544             return translet;
 545         }
 546         catch (InstantiationException e) {
 547             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
 548             throw new TransformerConfigurationException(err.toString());
 549         }
 550         catch (IllegalAccessException e) {
 551             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
 552             throw new TransformerConfigurationException(err.toString());
 553         }
 554     }
 555 
 556     /**
 557      * Implements JAXP's Templates.newTransformer()
 558      *
 559      * @throws TransformerConfigurationException
 560      */
 561     public synchronized Transformer newTransformer()
 562         throws TransformerConfigurationException
 563     {
 564         TransformerImpl transformer;
 565 
 566         transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
 567             _indentNumber, _tfactory);
 568 
 569         if (_uriResolver != null) {
 570             transformer.setURIResolver(_uriResolver);
 571         }
 572 
 573         if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 574             transformer.setSecureProcessing(true);
 575         }
 576         return transformer;
 577     }
 578 
 579     /**
 580      * Implements JAXP's Templates.getOutputProperties(). We need to
 581      * instanciate a translet to get the output settings, so
 582      * we might as well just instanciate a Transformer and use its
 583      * implementation of this method.
 584      */
 585     public synchronized Properties getOutputProperties() {
 586         try {
 587             return newTransformer().getOutputProperties();
 588         }
 589         catch (TransformerConfigurationException e) {
 590             return null;
 591         }
 592     }
 593 
 594     /**
 595      * Return the thread local copy of the stylesheet DOM.
 596      */
 597     public DOM getStylesheetDOM() {
 598         return (DOM)_sdom.get();
 599     }
 600 
 601     /**
 602      * Set the thread local copy of the stylesheet DOM.
 603      */
 604     public void setStylesheetDOM(DOM sdom) {
 605         _sdom.set(sdom);
 606     }
 607 }
--- EOF ---