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