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