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
30 import com.sun.org.apache.xalan.internal.utils.XMLSecurityPropertyManager.Property;
31 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
32 import com.sun.org.apache.xalan.internal.xsltc.compiler.SourceLoader;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
35 import com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager;
36 import com.sun.org.apache.xml.internal.utils.StopParseException;
37 import com.sun.org.apache.xml.internal.utils.StylesheetPIHandler;
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileNotFoundException;
41 import java.io.FilenameFilter;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.net.MalformedURLException;
45 import java.net.URL;
46 import java.util.ArrayList;
47 import java.util.Enumeration;
48 import java.util.Map;
49 import java.util.Properties;
50 import java.util.Vector;
51 import java.util.zip.ZipEntry;
52 import java.util.zip.ZipFile;
53 import javax.xml.XMLConstants;
54 import javax.xml.catalog.CatalogException;
55 import javax.xml.catalog.CatalogFeatures;
56 import javax.xml.catalog.CatalogFeatures.Feature;
57 import javax.xml.catalog.CatalogManager;
58 import javax.xml.catalog.CatalogResolver;
59 import javax.xml.parsers.SAXParser;
60 import javax.xml.parsers.SAXParserFactory;
61 import javax.xml.transform.ErrorListener;
62 import javax.xml.transform.Source;
63 import javax.xml.transform.Templates;
64 import javax.xml.transform.Transformer;
65 import javax.xml.transform.TransformerConfigurationException;
66 import javax.xml.transform.TransformerException;
67 import javax.xml.transform.TransformerFactory;
68 import javax.xml.transform.URIResolver;
69 import javax.xml.transform.dom.DOMResult;
70 import javax.xml.transform.dom.DOMSource;
133 */
134 private String _transletName = DEFAULT_TRANSLET_NAME;
135
136 /**
137 * The destination directory for the translet
138 */
139 private String _destinationDirectory = null;
140
141 /**
142 * The package name prefix for all generated translet classes
143 */
144 private static final String DEFAULT_TRANSLATE_PACKAGE = "die.verwandlung";
145 private String _packageName = DEFAULT_TRANSLATE_PACKAGE;
146
147 /**
148 * The jar file name which the translet classes are packaged into
149 */
150 private String _jarFileName = null;
151
152 /**
153 * This Map is used to store parameters for locating
154 * <?xml-stylesheet ...?> processing instructions in XML docs.
155 */
156 private Map<Source, PIParamWrapper> _piParams = null;
157
158 /**
159 * The above Map stores objects of this class.
160 */
161 private static class PIParamWrapper {
162 public String _media = null;
163 public String _title = null;
164 public String _charset = null;
165
166 public PIParamWrapper(String media, String title, String charset) {
167 _media = media;
168 _title = title;
169 _charset = charset;
170 }
171 }
172
173 /**
174 * Set to <code>true</code> when debugging is enabled.
175 */
176 private boolean _debug = false;
177
178 /**
179 * Set to <code>true</code> when templates are inlined.
180 */
181 private boolean _enableInlining = false;
182
183 /**
184 * Set to <code>true</code> when we want to generate
185 * translet classes from the stylesheet.
186 */
187 private boolean _generateTranslet = false;
188
189 /**
190 * If this is set to <code>true</code>, we attempt to use translet classes
191 * for transformation if possible without compiling the stylesheet. The
192 * translet class is only used if its timestamp is newer than the timestamp
193 * of the stylesheet.
194 */
195 private boolean _autoTranslet = false;
196
197 /**
198 * If this is set to <code>true</code>, we attempt to load the translet
199 * from the CLASSPATH.
200 */
201 private boolean _useClasspath = false;
202
203 /**
204 * Number of indent spaces when indentation is turned on.
205 */
206 private int _indentNumber = -1;
207
208 /**
209 * <p>State of secure processing feature.</p>
210 */
211 private boolean _isNotSecureProcessing = true;
212 /**
213 * <p>State of secure mode.</p>
214 */
215 private boolean _isSecureMode = false;
216
217 /**
218 * Indicates whether implementation parts should use
219 * service loader (or similar).
220 * Note the default value (false) is the safe option..
221 */
222 private boolean _useServicesMechanism;
223
224 /**
225 * protocols allowed for external references set by the stylesheet
226 * processing instruction, Import and Include element.
227 */
228 private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
229 /**
230 * protocols allowed for external DTD references in source file and/or stylesheet.
231 */
232 private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
233
234 private XMLSecurityPropertyManager _xmlSecurityPropertyMgr;
235 private XMLSecurityManager _xmlSecurityManager;
236
237 private final JdkXmlFeatures _xmlFeatures;
238
239 private ClassLoader _extensionClassLoader = null;
240
241 // Unmodifiable view of external extension function from xslt compiler
242 // It will be populated by user-specified extension functions during the
243 // type checking
244 private Map<String, Class<?>> _xsltcExtensionFunctions;
245
246 CatalogResolver _catalogUriResolver;
247 CatalogFeatures _catalogFeatures;
248 CatalogFeatures.Builder cfBuilder = CatalogFeatures.builder();
249 // Catalog features
549 * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
550 * </p>
551 *
552 * <p>See {@link javax.xml.transform.TransformerFactory} for full documentation of specific features.</p>
553 *
554 * @param name Feature name.
555 * @param value Is feature state <code>true</code> or <code>false</code>.
556 *
557 * @throws TransformerConfigurationException if this <code>TransformerFactory</code>
558 * or the <code>Transformer</code>s or <code>Template</code>s it creates cannot support this feature.
559 * @throws NullPointerException If the <code>name</code> parameter is null.
560 */
561 @Override
562 public void setFeature(String name, boolean value)
563 throws TransformerConfigurationException {
564
565 // feature name cannot be null
566 if (name == null) {
567 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SET_FEATURE_NULL_NAME);
568 throw new NullPointerException(err.toString());
569 }
570 // secure processing?
571 else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
572 if ((_isSecureMode) && (!value)) {
573 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SECUREPROCESSING_FEATURE);
574 throw new TransformerConfigurationException(err.toString());
575 }
576 _isNotSecureProcessing = !value;
577 _xmlSecurityManager.setSecureProcessing(value);
578
579 // set external access restriction when FSP is explicitly set
580 if (value) {
581 _xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD,
582 FeaturePropertyBase.State.FSP, XalanConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
583 _xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_STYLESHEET,
584 FeaturePropertyBase.State.FSP, XalanConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
585 _accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
586 Property.ACCESS_EXTERNAL_DTD);
587 _accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
588 Property.ACCESS_EXTERNAL_STYLESHEET);
589 }
590
591 if (value && _xmlFeatures != null) {
592 _xmlFeatures.setFeature(JdkXmlFeatures.XmlFeature.ENABLE_EXTENSION_FUNCTION,
593 JdkXmlFeatures.State.FSP, false);
594 }
595 }
596 else if (name.equals(XalanConstants.ORACLE_FEATURE_SERVICE_MECHANISM)) {
597 //in secure mode, let _useServicesMechanism be determined by the constructor
598 if (!_isSecureMode)
599 _useServicesMechanism = value;
600 }
601 else {
602 if (_xmlFeatures != null &&
603 _xmlFeatures.setFeature(name, JdkXmlFeatures.State.APIPROPERTY, value)) {
604 return;
605 }
606
607 // unknown feature
608 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNSUPPORTED_FEATURE, name);
609 throw new TransformerConfigurationException(err.toString());
610 }
611 }
612
613 /**
614 * javax.xml.transform.sax.TransformerFactory implementation.
615 * Look up the value of a feature (to see if it is supported).
616 * This method must be updated as the various methods and features of this
617 * class are implemented.
618 *
619 * @param name The feature name
620 * @return 'true' if feature is supported, 'false' if not
621 */
622 @Override
623 public boolean getFeature(String name) {
624 // All supported features should be listed here
625 String[] features = {
626 DOMSource.FEATURE,
627 DOMResult.FEATURE,
628 SAXSource.FEATURE,
629 SAXResult.FEATURE,
630 StAXSource.FEATURE,
631 StAXResult.FEATURE,
632 StreamSource.FEATURE,
633 StreamResult.FEATURE,
634 SAXTransformerFactory.FEATURE,
635 SAXTransformerFactory.FEATURE_XMLFILTER,
636 XalanConstants.ORACLE_FEATURE_SERVICE_MECHANISM
637 };
638
639 // feature name cannot be null
640 if (name == null) {
641 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_GET_FEATURE_NULL_NAME);
642 throw new NullPointerException(err.toString());
643 }
644
645 // Inefficient, but array is small
646 for (int i =0; i < features.length; i++) {
647 if (name.equals(features[i])) {
648 return true;
649 }
650 }
651
652 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
653 return !_isNotSecureProcessing;
654 }
655
656 /** Check to see if the property is managed by the JdkXmlFeatues **/
657 int index = _xmlFeatures.getIndex(name);
658 if (index > -1) {
659 return _xmlFeatures.getFeature(index);
660 }
661
662 // Feature not supported
663 return false;
664 }
665 /**
666 * Return the state of the services mechanism feature.
667 */
668 public boolean useServicesMechnism() {
669 return _useServicesMechanism;
670 }
671
672 /**
673 * @return the feature manager
674 */
675 public JdkXmlFeatures getJdkXmlFeatures() {
676 return _xmlFeatures;
677 }
678
679 /**
680 * javax.xml.transform.sax.TransformerFactory implementation.
681 * Get the object that is used by default during the transformation to
682 * resolve URIs used in document(), xsl:import, or xsl:include.
683 *
684 * @return The URLResolver used for this TransformerFactory and all
685 * Templates and Transformer objects created using this factory
686 */
687 @Override
688 public URIResolver getURIResolver() {
689 return _uriResolver;
690 }
691
692 /**
817
818 /**
819 * javax.xml.transform.sax.TransformerFactory implementation.
820 * Process the Source into a Templates object, which is a a compiled
821 * representation of the source. Note that this method should not be
822 * used with XSLTC, as the time-consuming compilation is done for each
823 * and every transformation.
824 *
825 * @return A Templates object that can be used to create Transformers.
826 * @throws TransformerConfigurationException
827 */
828 @Override
829 public Transformer newTransformer(Source source) throws
830 TransformerConfigurationException
831 {
832 final Templates templates = newTemplates(source);
833 final Transformer transformer = templates.newTransformer();
834 if (_uriResolver != null) {
835 transformer.setURIResolver(_uriResolver);
836 }
837 return(transformer);
838 }
839
840 /**
841 * Pass warning messages from the compiler to the error listener
842 */
843 private void passWarningsToListener(ArrayList<ErrorMsg> messages)
844 throws TransformerException
845 {
846 if (_errorListener == null || messages == null) {
847 return;
848 }
849 // Pass messages to listener, one by one
850 final int count = messages.size();
851 for (int pos = 0; pos < count; pos++) {
852 ErrorMsg msg = messages.get(pos);
853 // Workaround for the TCK failure ErrorListener.errorTests.error001.
854 if (msg.isWarningError())
855 _errorListener.error(
856 new TransformerConfigurationException(msg.toString()));
857 else
970
971 if (!_isNotSecureProcessing) xsltc.setSecureProcessing(true);
972 xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, _accessExternalStylesheet);
973 xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD);
974 xsltc.setProperty(XalanConstants.SECURITY_MANAGER, _xmlSecurityManager);
975 xsltc.setProperty(XalanConstants.JDK_EXTENSION_CLASSLOADER, _extensionClassLoader);
976
977 // set Catalog features
978 buildCatalogFeatures();
979 xsltc.setProperty(JdkXmlFeatures.CATALOG_FEATURES, _catalogFeatures);
980
981 xsltc.init();
982 if (!_isNotSecureProcessing)
983 _xsltcExtensionFunctions = xsltc.getExternalExtensionFunctions();
984 // Set a document loader (for xsl:include/import) if defined
985 if (_uriResolver != null || ( _catalogFiles != null
986 && _xmlFeatures.getFeature(JdkXmlFeatures.XmlFeature.USE_CATALOG))) {
987 xsltc.setSourceLoader(this);
988 }
989
990 // Pass parameters to the Parser to make sure it locates the correct
991 // <?xml-stylesheet ...?> PI in an XML input document
992 if ((_piParams != null) && (_piParams.get(source) != null)) {
993 // Get the parameters for this Source object
994 PIParamWrapper p = _piParams.get(source);
995 // Pass them on to the compiler (which will pass then to the parser)
996 if (p != null) {
997 xsltc.setPIParameters(p._media, p._title, p._charset);
998 }
999 }
1000
1001 // Set the attributes for translet generation
1002 int outputType = XSLTC.BYTEARRAY_OUTPUT;
1003 if (_generateTranslet || _autoTranslet) {
1004 // Set the translet name
1005 xsltc.setClassName(getTransletBaseName(source));
1006
1007 if (_destinationDirectory != null)
1008 xsltc.setDestDirectory(_destinationDirectory);
1009 else {
1010 String xslName = getStylesheetFileName(source);
1011 if (xslName != null) {
1012 File xslFile = new File(xslName);
1013 String xslDir = xslFile.getParent();
1014
1015 if (xslDir != null)
1016 xsltc.setDestDirectory(xslDir);
1017 }
1018 }
1019
1020 if (_packageName != null)
1425 transletPath = transletPath + ".class";
1426 }
1427
1428 // Return null if the translet class file does not exist.
1429 File transletFile = new File(transletPath);
1430 if (!transletFile.exists())
1431 return null;
1432
1433 // Compare the timestamps of the translet and the xsl file.
1434 // If the translet is older than the xsl file, return null
1435 // so that the xsl file is used for the transformation and
1436 // the translet is regenerated.
1437 if (xslFile != null && xslFile.exists()) {
1438 long xslTimestamp = xslFile.lastModified();
1439 long transletTimestamp = transletFile.lastModified();
1440 if (transletTimestamp < xslTimestamp)
1441 return null;
1442 }
1443
1444 // Load the translet into a bytecode array.
1445 Vector bytecodes = new Vector();
1446 int fileLength = (int)transletFile.length();
1447 if (fileLength > 0) {
1448 FileInputStream input;
1449 try {
1450 input = new FileInputStream(transletFile);
1451 }
1452 catch (FileNotFoundException e) {
1453 return null;
1454 }
1455
1456 byte[] bytes = new byte[fileLength];
1457 try {
1458 readFromInputStream(bytes, input, fileLength);
1459 input.close();
1460 }
1461 catch (IOException e) {
1462 return null;
1463 }
1464
1465 bytecodes.addElement(bytes);
1466 }
1467 else
1468 return null;
1469
1470 // Find the parent directory of the translet.
1471 String transletParentDir = transletFile.getParent();
1472 if (transletParentDir == null)
1473 transletParentDir = SecuritySupport.getSystemProperty("user.dir");
1474
1475 File transletParentFile = new File(transletParentDir);
1476
1477 // Find all the auxiliary files which have a name pattern of "transletClass$nnn.class".
1478 final String transletAuxPrefix = transletName + "$";
1479 File[] auxfiles = transletParentFile.listFiles(new FilenameFilter() {
1480 @Override
1481 public boolean accept(File dir, String name)
1482 {
1483 return (name.endsWith(".class") && name.startsWith(transletAuxPrefix));
1484 }
1485 });
1486
1487 // Load the auxiliary class files and add them to the bytecode array.
1488 for (int i = 0; i < auxfiles.length; i++)
1491 int auxlength = (int)auxfile.length();
1492 if (auxlength > 0) {
1493 FileInputStream auxinput = null;
1494 try {
1495 auxinput = new FileInputStream(auxfile);
1496 }
1497 catch (FileNotFoundException e) {
1498 continue;
1499 }
1500
1501 byte[] bytes = new byte[auxlength];
1502
1503 try {
1504 readFromInputStream(bytes, auxinput, auxlength);
1505 auxinput.close();
1506 }
1507 catch (IOException e) {
1508 continue;
1509 }
1510
1511 bytecodes.addElement(bytes);
1512 }
1513 }
1514
1515 // Convert the Vector of byte[] to byte[][].
1516 final int count = bytecodes.size();
1517 if ( count > 0) {
1518 final byte[][] result = new byte[count][1];
1519 for (int i = 0; i < count; i++) {
1520 result[i] = (byte[])bytecodes.elementAt(i);
1521 }
1522
1523 return result;
1524 }
1525 else
1526 return null;
1527 }
1528
1529 /**
1530 * Load the translet classes from the jar file and return the bytecode.
1531 *
1532 * @param source The xsl source
1533 * @param fullClassName The full name of the translet
1534 * @return The bytecode array
1535 */
1536 private byte[][] getBytecodesFromJar(Source source, String fullClassName)
1537 {
1538 String xslFileName = getStylesheetFileName(source);
1539 File xslFile = null;
1540 if (xslFileName != null)
1549 jarPath = xslFile.getParent() + "/" + _jarFileName;
1550 else
1551 jarPath = _jarFileName;
1552 }
1553
1554 // Return null if the jar file does not exist.
1555 File file = new File(jarPath);
1556 if (!file.exists())
1557 return null;
1558
1559 // Compare the timestamps of the jar file and the xsl file. Return null
1560 // if the xsl file is newer than the jar file.
1561 if (xslFile != null && xslFile.exists()) {
1562 long xslTimestamp = xslFile.lastModified();
1563 long transletTimestamp = file.lastModified();
1564 if (transletTimestamp < xslTimestamp)
1565 return null;
1566 }
1567
1568 // Create a ZipFile object for the jar file
1569 ZipFile jarFile;
1570 try {
1571 jarFile = new ZipFile(file);
1572 }
1573 catch (IOException e) {
1574 return null;
1575 }
1576
1577 String transletPath = fullClassName.replace('.', '/');
1578 String transletAuxPrefix = transletPath + "$";
1579 String transletFullName = transletPath + ".class";
1580
1581 Vector bytecodes = new Vector();
1582
1583 // Iterate through all entries in the jar file to find the
1584 // translet and auxiliary classes.
1585 Enumeration entries = jarFile.entries();
1586 while (entries.hasMoreElements())
1587 {
1588 ZipEntry entry = (ZipEntry)entries.nextElement();
1589 String entryName = entry.getName();
1590 if (entry.getSize() > 0 &&
1591 (entryName.equals(transletFullName) ||
1592 (entryName.endsWith(".class") &&
1593 entryName.startsWith(transletAuxPrefix))))
1594 {
1595 try {
1596 InputStream input = jarFile.getInputStream(entry);
1597 int size = (int)entry.getSize();
1598 byte[] bytes = new byte[size];
1599 readFromInputStream(bytes, input, size);
1600 input.close();
1601 bytecodes.addElement(bytes);
1602 }
1603 catch (IOException e) {
1604 return null;
1605 }
1606 }
1607 }
1608
1609 // Convert the Vector of byte[] to byte[][].
1610 final int count = bytecodes.size();
1611 if (count > 0) {
1612 final byte[][] result = new byte[count][1];
1613 for (int i = 0; i < count; i++) {
1614 result[i] = (byte[])bytecodes.elementAt(i);
1615 }
1616
1617 return result;
1618 }
1619 else
1620 return null;
1621 }
1622
1623 /**
1624 * Read a given number of bytes from the InputStream into a byte array.
1625 *
1626 * @param bytes The byte array to store the input content.
1627 * @param input The input stream.
1628 * @param size The number of bytes to read.
1629 */
1630 private void readFromInputStream(byte[] bytes, InputStream input, int size)
1631 throws IOException
1632 {
1633 int n = 0;
1634 int offset = 0;
1635 int length = size;
1636 while (length > 0 && (n = input.read(bytes, offset, length)) > 0) {
1637 offset = offset + n;
1638 length = length - n;
1639 }
1640 }
1641
1642 /**
1643 * Return the base class name of the translet.
1644 * The translet name is resolved using the following rules:
1645 * 1. if the _transletName attribute is set and its value is not "GregorSamsa",
1646 * then _transletName is returned.
1647 * 2. otherwise get the translet name from the base name of the system ID
1648 * 3. return "GregorSamsa" if the result from step 2 is null.
1649 *
1650 * @param source The input Source
1651 * @return The name of the translet class
1652 */
1653 private String getTransletBaseName(Source source)
1654 {
1655 String transletBaseName = null;
1656 if (!_transletName.equals(DEFAULT_TRANSLET_NAME))
1657 return _transletName;
1658 else {
1659 String systemId = source.getSystemId();
1660 if (systemId != null) {
1661 String baseName = Util.baseName(systemId);
1662 if (baseName != null) {
1663 baseName = Util.noExtName(baseName);
1664 transletBaseName = Util.toJavaName(baseName);
1665 }
1666 }
1667 }
1668
1669 return (transletBaseName != null) ? transletBaseName : DEFAULT_TRANSLET_NAME;
1670 }
1671
1672 /**
1673 * Return the local file name from the systemId of the Source object
1674 *
1675 * @param source The Source
1676 * @return The file name in the local filesystem, or null if the
1677 * systemId does not represent a local file.
1678 */
1679 private String getStylesheetFileName(Source source)
1680 {
1681 String systemId = source.getSystemId();
1682 if (systemId != null) {
1683 File file = new File(systemId);
1684 if (file.exists())
1685 return systemId;
1686 else {
1687 URL url;
1688 try {
1689 url = new URL(systemId);
1690 }
1691 catch (MalformedURLException e) {
1692 return null;
1693 }
1694
1695 if ("file".equals(url.getProtocol()))
1696 return url.getFile();
1697 else
1698 return null;
1699 }
1700 }
1701 else
1702 return null;
1703 }
1704
1705 /**
1706 * Returns a new instance of the XSLTC DTM Manager service.
1707 */
1708 protected final XSLTCDTMManager createNewDTMManagerInstance() {
1709 return XSLTCDTMManager.createNewDTMManagerInstance();
1710 }
1711 }
|
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 package com.sun.org.apache.xalan.internal.xsltc.trax;
22
30 import com.sun.org.apache.xalan.internal.utils.XMLSecurityPropertyManager.Property;
31 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
32 import com.sun.org.apache.xalan.internal.xsltc.compiler.SourceLoader;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
35 import com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager;
36 import com.sun.org.apache.xml.internal.utils.StopParseException;
37 import com.sun.org.apache.xml.internal.utils.StylesheetPIHandler;
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileNotFoundException;
41 import java.io.FilenameFilter;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.net.MalformedURLException;
45 import java.net.URL;
46 import java.util.ArrayList;
47 import java.util.Enumeration;
48 import java.util.Map;
49 import java.util.Properties;
50 import java.util.zip.ZipEntry;
51 import java.util.zip.ZipFile;
52 import javax.xml.XMLConstants;
53 import javax.xml.catalog.CatalogException;
54 import javax.xml.catalog.CatalogFeatures;
55 import javax.xml.catalog.CatalogFeatures.Feature;
56 import javax.xml.catalog.CatalogManager;
57 import javax.xml.catalog.CatalogResolver;
58 import javax.xml.parsers.SAXParser;
59 import javax.xml.parsers.SAXParserFactory;
60 import javax.xml.transform.ErrorListener;
61 import javax.xml.transform.Source;
62 import javax.xml.transform.Templates;
63 import javax.xml.transform.Transformer;
64 import javax.xml.transform.TransformerConfigurationException;
65 import javax.xml.transform.TransformerException;
66 import javax.xml.transform.TransformerFactory;
67 import javax.xml.transform.URIResolver;
68 import javax.xml.transform.dom.DOMResult;
69 import javax.xml.transform.dom.DOMSource;
132 */
133 private String _transletName = DEFAULT_TRANSLET_NAME;
134
135 /**
136 * The destination directory for the translet
137 */
138 private String _destinationDirectory = null;
139
140 /**
141 * The package name prefix for all generated translet classes
142 */
143 private static final String DEFAULT_TRANSLATE_PACKAGE = "die.verwandlung";
144 private String _packageName = DEFAULT_TRANSLATE_PACKAGE;
145
146 /**
147 * The jar file name which the translet classes are packaged into
148 */
149 private String _jarFileName = null;
150
151 /**
152 * Set to <code>true</code> when debugging is enabled.
153 */
154 private boolean _debug = false;
155
156 /**
157 * Set to <code>true</code> when templates are inlined.
158 */
159 private boolean _enableInlining = false;
160
161 /**
162 * Set to <code>true</code> when we want to generate
163 * translet classes from the stylesheet.
164 */
165 private boolean _generateTranslet = false;
166
167 /**
168 * If this is set to <code>true</code>, we attempt to use translet classes
169 * for transformation if possible without compiling the stylesheet. The
170 * translet class is only used if its timestamp is newer than the timestamp
171 * of the stylesheet.
172 */
173 private boolean _autoTranslet = false;
174
175 /**
176 * If this is set to <code>true</code>, we attempt to load the translet
177 * from the CLASSPATH.
178 */
179 private boolean _useClasspath = false;
180
181 /**
182 * Number of indent spaces when indentation is turned on.
183 */
184 private int _indentNumber = -1;
185
186 /**
187 * <p>State of secure processing feature.</p>
188 */
189 private boolean _isNotSecureProcessing = true;
190
191 /**
192 * <p>State of secure mode.</p>
193 */
194 private boolean _isSecureMode = false;
195
196 /**
197 * Indicates whether implementation parts should use
198 * service loader (or similar).
199 * Note the default value (false) is the safe option.
200 */
201 private boolean _useServicesMechanism;
202
203 /**
204 * protocols allowed for external references set by the stylesheet
205 * processing instruction, Import and Include element.
206 */
207 private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
208
209 /**
210 * protocols allowed for external DTD references in source file and/or stylesheet.
211 */
212 private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
213
214 private XMLSecurityPropertyManager _xmlSecurityPropertyMgr;
215 private XMLSecurityManager _xmlSecurityManager;
216
217 private final JdkXmlFeatures _xmlFeatures;
218
219 private ClassLoader _extensionClassLoader = null;
220
221 // Unmodifiable view of external extension function from xslt compiler
222 // It will be populated by user-specified extension functions during the
223 // type checking
224 private Map<String, Class<?>> _xsltcExtensionFunctions;
225
226 CatalogResolver _catalogUriResolver;
227 CatalogFeatures _catalogFeatures;
228 CatalogFeatures.Builder cfBuilder = CatalogFeatures.builder();
229 // Catalog features
529 * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
530 * </p>
531 *
532 * <p>See {@link javax.xml.transform.TransformerFactory} for full documentation of specific features.</p>
533 *
534 * @param name Feature name.
535 * @param value Is feature state <code>true</code> or <code>false</code>.
536 *
537 * @throws TransformerConfigurationException if this <code>TransformerFactory</code>
538 * or the <code>Transformer</code>s or <code>Template</code>s it creates cannot support this feature.
539 * @throws NullPointerException If the <code>name</code> parameter is null.
540 */
541 @Override
542 public void setFeature(String name, boolean value)
543 throws TransformerConfigurationException {
544
545 // feature name cannot be null
546 if (name == null) {
547 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SET_FEATURE_NULL_NAME);
548 throw new NullPointerException(err.toString());
549 // secure processing?
550 } else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
551 if ((_isSecureMode) && (!value)) {
552 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SECUREPROCESSING_FEATURE);
553 throw new TransformerConfigurationException(err.toString());
554 }
555 _isNotSecureProcessing = !value;
556 _xmlSecurityManager.setSecureProcessing(value);
557
558 // set external access restriction when FSP is explicitly set
559 if (value) {
560 _xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD,
561 FeaturePropertyBase.State.FSP, XalanConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
562 _xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_STYLESHEET,
563 FeaturePropertyBase.State.FSP, XalanConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
564 _accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
565 Property.ACCESS_EXTERNAL_DTD);
566 _accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
567 Property.ACCESS_EXTERNAL_STYLESHEET);
568 }
569
570 if (value && _xmlFeatures != null) {
571 _xmlFeatures.setFeature(JdkXmlFeatures.XmlFeature.ENABLE_EXTENSION_FUNCTION,
572 JdkXmlFeatures.State.FSP, false);
573 }
574 } else if (name.equals(XalanConstants.ORACLE_FEATURE_SERVICE_MECHANISM)) {
575 //in secure mode, let _useServicesMechanism be determined by the constructor
576 if (!_isSecureMode)
577 _useServicesMechanism = value;
578 } else {
579 if (_xmlFeatures != null &&
580 _xmlFeatures.setFeature(name, JdkXmlFeatures.State.APIPROPERTY, value)) {
581 return;
582 }
583
584 // unknown feature
585 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNSUPPORTED_FEATURE, name);
586 throw new TransformerConfigurationException(err.toString());
587 }
588 }
589
590 /**
591 * javax.xml.transform.sax.TransformerFactory implementation.
592 * Look up the value of a feature (to see if it is supported).
593 * This method must be updated as the various methods and features of this
594 * class are implemented.
595 *
596 * @param name The feature name
597 * @return 'true' if feature is supported, 'false' if not
598 */
599 @Override
600 public boolean getFeature(String name) {
601 // all supported features should be listed here
602 String[] features = {
603 DOMSource.FEATURE,
604 DOMResult.FEATURE,
605 SAXSource.FEATURE,
606 SAXResult.FEATURE,
607 StAXSource.FEATURE,
608 StAXResult.FEATURE,
609 StreamSource.FEATURE,
610 StreamResult.FEATURE,
611 SAXTransformerFactory.FEATURE,
612 SAXTransformerFactory.FEATURE_XMLFILTER,
613 XalanConstants.ORACLE_FEATURE_SERVICE_MECHANISM
614 };
615
616 // feature name cannot be null
617 if (name == null) {
618 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_GET_FEATURE_NULL_NAME);
619 throw new NullPointerException(err.toString());
620 }
621
622 // Inefficient, but array is small
623 for (int i = 0; i < features.length; i++) {
624 if (name.equals(features[i])) {
625 return true;
626 }
627 }
628
629 // secure processing?
630 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
631 return !_isNotSecureProcessing;
632 }
633
634 // check to see if the property is managed by the JdkXmlFeatues
635 int index = _xmlFeatures.getIndex(name);
636 if (index > -1) {
637 return _xmlFeatures.getFeature(index);
638 }
639
640 // feature not supported
641 return false;
642 }
643
644 /**
645 * Return the state of the services mechanism feature.
646 */
647 public boolean useServicesMechnism() {
648 return _useServicesMechanism;
649 }
650
651 /**
652 * @return the feature manager
653 */
654 public JdkXmlFeatures getJdkXmlFeatures() {
655 return _xmlFeatures;
656 }
657
658 /**
659 * javax.xml.transform.sax.TransformerFactory implementation.
660 * Get the object that is used by default during the transformation to
661 * resolve URIs used in document(), xsl:import, or xsl:include.
662 *
663 * @return The URLResolver used for this TransformerFactory and all
664 * Templates and Transformer objects created using this factory
665 */
666 @Override
667 public URIResolver getURIResolver() {
668 return _uriResolver;
669 }
670
671 /**
796
797 /**
798 * javax.xml.transform.sax.TransformerFactory implementation.
799 * Process the Source into a Templates object, which is a a compiled
800 * representation of the source. Note that this method should not be
801 * used with XSLTC, as the time-consuming compilation is done for each
802 * and every transformation.
803 *
804 * @return A Templates object that can be used to create Transformers.
805 * @throws TransformerConfigurationException
806 */
807 @Override
808 public Transformer newTransformer(Source source) throws
809 TransformerConfigurationException
810 {
811 final Templates templates = newTemplates(source);
812 final Transformer transformer = templates.newTransformer();
813 if (_uriResolver != null) {
814 transformer.setURIResolver(_uriResolver);
815 }
816 return transformer;
817 }
818
819 /**
820 * Pass warning messages from the compiler to the error listener
821 */
822 private void passWarningsToListener(ArrayList<ErrorMsg> messages)
823 throws TransformerException
824 {
825 if (_errorListener == null || messages == null) {
826 return;
827 }
828 // Pass messages to listener, one by one
829 final int count = messages.size();
830 for (int pos = 0; pos < count; pos++) {
831 ErrorMsg msg = messages.get(pos);
832 // Workaround for the TCK failure ErrorListener.errorTests.error001.
833 if (msg.isWarningError())
834 _errorListener.error(
835 new TransformerConfigurationException(msg.toString()));
836 else
949
950 if (!_isNotSecureProcessing) xsltc.setSecureProcessing(true);
951 xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, _accessExternalStylesheet);
952 xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD);
953 xsltc.setProperty(XalanConstants.SECURITY_MANAGER, _xmlSecurityManager);
954 xsltc.setProperty(XalanConstants.JDK_EXTENSION_CLASSLOADER, _extensionClassLoader);
955
956 // set Catalog features
957 buildCatalogFeatures();
958 xsltc.setProperty(JdkXmlFeatures.CATALOG_FEATURES, _catalogFeatures);
959
960 xsltc.init();
961 if (!_isNotSecureProcessing)
962 _xsltcExtensionFunctions = xsltc.getExternalExtensionFunctions();
963 // Set a document loader (for xsl:include/import) if defined
964 if (_uriResolver != null || ( _catalogFiles != null
965 && _xmlFeatures.getFeature(JdkXmlFeatures.XmlFeature.USE_CATALOG))) {
966 xsltc.setSourceLoader(this);
967 }
968
969 // Set the attributes for translet generation
970 int outputType = XSLTC.BYTEARRAY_OUTPUT;
971 if (_generateTranslet || _autoTranslet) {
972 // Set the translet name
973 xsltc.setClassName(getTransletBaseName(source));
974
975 if (_destinationDirectory != null)
976 xsltc.setDestDirectory(_destinationDirectory);
977 else {
978 String xslName = getStylesheetFileName(source);
979 if (xslName != null) {
980 File xslFile = new File(xslName);
981 String xslDir = xslFile.getParent();
982
983 if (xslDir != null)
984 xsltc.setDestDirectory(xslDir);
985 }
986 }
987
988 if (_packageName != null)
1393 transletPath = transletPath + ".class";
1394 }
1395
1396 // Return null if the translet class file does not exist.
1397 File transletFile = new File(transletPath);
1398 if (!transletFile.exists())
1399 return null;
1400
1401 // Compare the timestamps of the translet and the xsl file.
1402 // If the translet is older than the xsl file, return null
1403 // so that the xsl file is used for the transformation and
1404 // the translet is regenerated.
1405 if (xslFile != null && xslFile.exists()) {
1406 long xslTimestamp = xslFile.lastModified();
1407 long transletTimestamp = transletFile.lastModified();
1408 if (transletTimestamp < xslTimestamp)
1409 return null;
1410 }
1411
1412 // Load the translet into a bytecode array.
1413 ArrayList<byte[]> bytecodes = new ArrayList<>();
1414 int fileLength = (int)transletFile.length();
1415 if (fileLength > 0) {
1416 FileInputStream input;
1417 try {
1418 input = new FileInputStream(transletFile);
1419 }
1420 catch (FileNotFoundException e) {
1421 return null;
1422 }
1423
1424 byte[] bytes = new byte[fileLength];
1425 try {
1426 readFromInputStream(bytes, input, fileLength);
1427 input.close();
1428 }
1429 catch (IOException e) {
1430 return null;
1431 }
1432
1433 bytecodes.add(bytes);
1434 } else {
1435 return null;
1436 }
1437
1438 // Find the parent directory of the translet.
1439 String transletParentDir = transletFile.getParent();
1440 if (transletParentDir == null)
1441 transletParentDir = SecuritySupport.getSystemProperty("user.dir");
1442
1443 File transletParentFile = new File(transletParentDir);
1444
1445 // Find all the auxiliary files which have a name pattern of "transletClass$nnn.class".
1446 final String transletAuxPrefix = transletName + "$";
1447 File[] auxfiles = transletParentFile.listFiles(new FilenameFilter() {
1448 @Override
1449 public boolean accept(File dir, String name)
1450 {
1451 return (name.endsWith(".class") && name.startsWith(transletAuxPrefix));
1452 }
1453 });
1454
1455 // Load the auxiliary class files and add them to the bytecode array.
1456 for (int i = 0; i < auxfiles.length; i++)
1459 int auxlength = (int)auxfile.length();
1460 if (auxlength > 0) {
1461 FileInputStream auxinput = null;
1462 try {
1463 auxinput = new FileInputStream(auxfile);
1464 }
1465 catch (FileNotFoundException e) {
1466 continue;
1467 }
1468
1469 byte[] bytes = new byte[auxlength];
1470
1471 try {
1472 readFromInputStream(bytes, auxinput, auxlength);
1473 auxinput.close();
1474 }
1475 catch (IOException e) {
1476 continue;
1477 }
1478
1479 bytecodes.add(bytes);
1480 }
1481 }
1482
1483 // Convert the Vector of byte[] to byte[][].
1484 final int count = bytecodes.size();
1485 if ( count > 0) {
1486 final byte[][] result = new byte[count][1];
1487 for (int i = 0; i < count; i++) {
1488 result[i] = bytecodes.get(i);
1489 }
1490
1491 return result;
1492 }
1493 else
1494 return null;
1495 }
1496
1497 /**
1498 * Load the translet classes from the jar file and return the bytecode.
1499 *
1500 * @param source The xsl source
1501 * @param fullClassName The full name of the translet
1502 * @return The bytecode array
1503 */
1504 private byte[][] getBytecodesFromJar(Source source, String fullClassName)
1505 {
1506 String xslFileName = getStylesheetFileName(source);
1507 File xslFile = null;
1508 if (xslFileName != null)
1517 jarPath = xslFile.getParent() + "/" + _jarFileName;
1518 else
1519 jarPath = _jarFileName;
1520 }
1521
1522 // Return null if the jar file does not exist.
1523 File file = new File(jarPath);
1524 if (!file.exists())
1525 return null;
1526
1527 // Compare the timestamps of the jar file and the xsl file. Return null
1528 // if the xsl file is newer than the jar file.
1529 if (xslFile != null && xslFile.exists()) {
1530 long xslTimestamp = xslFile.lastModified();
1531 long transletTimestamp = file.lastModified();
1532 if (transletTimestamp < xslTimestamp)
1533 return null;
1534 }
1535
1536 // Create a ZipFile object for the jar file
1537 try (ZipFile jarFile = new ZipFile(file)) {
1538 String transletPath = fullClassName.replace('.', '/');
1539 String transletAuxPrefix = transletPath + "$";
1540 String transletFullName = transletPath + ".class";
1541
1542 ArrayList<byte[]> bytecodes = new ArrayList<>();
1543
1544 // Iterate through all entries in the jar file to find the
1545 // translet and auxiliary classes.
1546 Enumeration<? extends ZipEntry> entries = jarFile.entries();
1547 while (entries.hasMoreElements()) {
1548 ZipEntry entry = entries.nextElement();
1549 String entryName = entry.getName();
1550 if (entry.getSize() > 0 &&
1551 (entryName.equals(transletFullName) ||
1552 (entryName.endsWith(".class") &&
1553 entryName.startsWith(transletAuxPrefix))))
1554 {
1555 InputStream input = jarFile.getInputStream(entry);
1556 int size = (int)entry.getSize();
1557 byte[] bytes = new byte[size];
1558 readFromInputStream(bytes, input, size);
1559 input.close();
1560 bytecodes.add(bytes);
1561 }
1562 }
1563
1564 // Convert the Vector of byte[] to byte[][].
1565 final int count = bytecodes.size();
1566 if (count > 0) {
1567 final byte[][] result = new byte[count][1];
1568 for (int i = 0; i < count; i++) {
1569 result[i] = bytecodes.get(i);
1570 }
1571 return result;
1572 } else {
1573 return null;
1574 }
1575 } catch (IOException e) {
1576 return null;
1577 }
1578 }
1579
1580 /**
1581 * Read a given number of bytes from the InputStream into a byte array.
1582 *
1583 * @param bytes The byte array to store the input content.
1584 * @param input The input stream.
1585 * @param size The number of bytes to read.
1586 */
1587 private void readFromInputStream(byte[] bytes, InputStream input, int size)
1588 throws IOException
1589 {
1590 int n = 0;
1591 int offset = 0;
1592 int length = size;
1593 while (length > 0 && (n = input.read(bytes, offset, length)) > 0) {
1594 offset = offset + n;
1595 length = length - n;
1596 }
1597 }
1598
1599 /**
1600 * Return the base class name of the translet.
1601 * The translet name is resolved using the following rules:
1602 * 1. if the _transletName attribute is set and its value is not "GregorSamsa",
1603 * then _transletName is returned.
1604 * 2. otherwise get the translet name from the base name of the system ID
1605 * 3. return "GregorSamsa" if the result from step 2 is null.
1606 *
1607 * @param source The input Source
1608 * @return The name of the translet class
1609 */
1610 private String getTransletBaseName(Source source) {
1611 String transletBaseName = null;
1612 if (!_transletName.equals(DEFAULT_TRANSLET_NAME))
1613 return _transletName;
1614 else {
1615 String systemId = source.getSystemId();
1616 if (systemId != null) {
1617 String baseName = Util.baseName(systemId);
1618 if (baseName != null) {
1619 baseName = Util.noExtName(baseName);
1620 transletBaseName = Util.toJavaName(baseName);
1621 }
1622 }
1623 }
1624
1625 return (transletBaseName != null) ? transletBaseName : DEFAULT_TRANSLET_NAME;
1626 }
1627
1628 /**
1629 * Return the local file name from the systemId of the Source object
1630 *
1631 * @param source The Source
1632 * @return The file name in the local filesystem, or null if the
1633 * systemId does not represent a local file.
1634 */
1635 private String getStylesheetFileName(Source source) {
1636 String systemId = source.getSystemId();
1637 if (systemId != null) {
1638 File file = new File(systemId);
1639 if (file.exists())
1640 return systemId;
1641 else {
1642 URL url;
1643 try {
1644 url = new URL(systemId);
1645 }
1646 catch (MalformedURLException e) {
1647 return null;
1648 }
1649
1650 if ("file".equals(url.getProtocol()))
1651 return url.getFile();
1652 else
1653 return null;
1654 }
1655 } else {
1656 return null;
1657 }
1658 }
1659
1660 /**
1661 * Returns a new instance of the XSLTC DTM Manager service.
1662 */
1663 protected final XSLTCDTMManager createNewDTMManagerInstance() {
1664 return XSLTCDTMManager.createNewDTMManagerInstance();
1665 }
1666 }
|