package com.sun.org.apache.xalan.internal.xsltc.trax;
import com.sun.org.apache.xalan.internal.XalanConstants;
import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.Translet;
import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.RuntimePermission;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import javax.xml.XMLConstants;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.URIResolver;
import jdk.xml.internal.SecuritySupport;
public final class TemplatesImpl implements Templates, Serializable {
static final long serialVersionUID = 673094361519270707L;
public final static String DESERIALIZE_TRANSLET = "jdk.xml.enableTemplatesImplDeserialization";
private static String ABSTRACT_TRANSLET
= "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
private String _name = null;
private byte[][] _bytecodes = null;
private Class<?>[] _class = null;
private int _transletIndex = -1;
private transient Map<String, Class<?>> _auxClasses = null;
private Properties _outputProperties;
private int _indentNumber;
private transient URIResolver _uriResolver = null;
private transient ThreadLocal<DOM> _sdom = new ThreadLocal<>();
private transient TransformerFactoryImpl _tfactory = null;
private transient boolean _overrideDefaultParser;
private transient String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[] {
new ObjectStreamField("_name", String.class),
new ObjectStreamField("_bytecodes", byte[][].class),
new ObjectStreamField("_class", Class[].class),
new ObjectStreamField("_transletIndex", int.class),
new ObjectStreamField("_outputProperties", Properties.class),
new ObjectStreamField("_indentNumber", int.class),
};
static final class TransletClassLoader extends ClassLoader {
private final Map<String, Class<?>> _loadedExternalExtensionFunctions;
TransletClassLoader(ClassLoader parent) {
super(parent);
_loadedExternalExtensionFunctions = null;
}
TransletClassLoader(ClassLoader parent, Map<String, Class<?>> mapEF) {
super(parent);
_loadedExternalExtensionFunctions = mapEF;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> ret = null;
if (_loadedExternalExtensionFunctions != null) {
ret = _loadedExternalExtensionFunctions.get(name);
}
if (ret == null) {
ret = super.loadClass(name);
}
return ret;
}
Class<?> defineClass(final byte[] b) {
return defineClass(null, b, 0, b.length);
}
Class<?> defineClass(final byte[] b, ProtectionDomain pd) {
return defineClass(null, b, 0, b.length, pd);
}
}
protected TemplatesImpl(byte[][] bytecodes, String transletName,
Properties outputProperties, int indentNumber,
TransformerFactoryImpl tfactory)
{
_bytecodes = bytecodes;
init(transletName, outputProperties, indentNumber, tfactory);
}
protected TemplatesImpl(Class<?>[] transletClasses, String transletName,
Properties outputProperties, int indentNumber,
TransformerFactoryImpl tfactory)
{
_class = transletClasses;
_transletIndex = 0;
init(transletName, outputProperties, indentNumber, tfactory);
}
private void init(String transletName,
Properties outputProperties, int indentNumber,
TransformerFactoryImpl tfactory) {
_name = transletName;
_outputProperties = outputProperties;
_indentNumber = indentNumber;
_tfactory = tfactory;
_overrideDefaultParser = tfactory.overrideDefaultParser();
_accessExternalStylesheet = (String) tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
}
public TemplatesImpl() { }
@SuppressWarnings("unchecked")
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException
{
SecurityManager security = System.getSecurityManager();
if (security != null){
String temp = SecuritySupport.getSystemProperty(DESERIALIZE_TRANSLET);
if (temp == null || !(temp.length()==0 || temp.equalsIgnoreCase("true"))) {
ErrorMsg err = new ErrorMsg(ErrorMsg.DESERIALIZE_TRANSLET_ERR);
throw new UnsupportedOperationException(err.toString());
}
}
ObjectInputStream.GetField gf = is.readFields();
_name = (String)gf.get("_name", null);
_bytecodes = (byte[][])gf.get("_bytecodes", null);
_class = (Class<?>[])gf.get("_class", null);
_transletIndex = gf.get("_transletIndex", -1);
_outputProperties = (Properties)gf.get("_outputProperties", null);
_indentNumber = gf.get("_indentNumber", 0);
if (is.readBoolean()) {
_uriResolver = (URIResolver) is.readObject();
}
_tfactory = new TransformerFactoryImpl();
}
private void writeObject(ObjectOutputStream os)
throws IOException, ClassNotFoundException {
if (_auxClasses != null) {
throw new NotSerializableException(
"com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable");
}
ObjectOutputStream.PutField pf = os.putFields();
pf.put("_name", _name);
pf.put("_bytecodes", _bytecodes);
pf.put("_class", _class);
pf.put("_transletIndex", _transletIndex);
pf.put("_outputProperties", _outputProperties);
pf.put("_indentNumber", _indentNumber);
os.writeFields();
if (_uriResolver instanceof Serializable) {
os.writeBoolean(true);
os.writeObject((Serializable) _uriResolver);
}
else {
os.writeBoolean(false);
}
}
public boolean overrideDefaultParser() {
return _overrideDefaultParser;
}
public synchronized void setURIResolver(URIResolver resolver) {
_uriResolver = resolver;
}
private synchronized void setTransletBytecodes(byte[][] bytecodes) {
_bytecodes = bytecodes;
}
private synchronized byte[][] getTransletBytecodes() {
return _bytecodes;
}
private synchronized Class<?>[] getTransletClasses() {
try {
if (_class == null) defineTransletClasses();
}
catch (TransformerConfigurationException e) {
}
return _class;
}
public synchronized int getTransletIndex() {
try {
if (_class == null) defineTransletClasses();
}
catch (TransformerConfigurationException e) {
}
return _transletIndex;
}
protected synchronized void setTransletName(String name) {
_name = name;
}
protected synchronized String getTransletName() {
return _name;
}
private Module createModule(ModuleDescriptor descriptor, ClassLoader loader) {
String mn = descriptor.name();
ModuleReference mref = new ModuleReference(descriptor, null) {
@Override
public ModuleReader open() {
throw new UnsupportedOperationException();
}
};
ModuleFinder finder = new ModuleFinder() {
@Override
public Optional<ModuleReference> find(String name) {
if (name.equals(mn)) {
return Optional.of(mref);
} else {
return Optional.empty();
}
}
@Override
public Set<ModuleReference> findAll() {
return Set.of(mref);
}
};
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration cf = bootLayer.configuration()
.resolve(finder, ModuleFinder.of(), Set.of(mn));
PrivilegedAction<ModuleLayer> pa = () -> bootLayer.defineModules(cf, name -> loader);
ModuleLayer layer = AccessController.doPrivileged(pa);
Module m = layer.findModule(mn).get();
assert m.getLayer() == layer;
return m;
}
private void defineTransletClasses()
throws TransformerConfigurationException {
if (_bytecodes == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
}
TransletClassLoader loader =
AccessController.doPrivileged(new PrivilegedAction<TransletClassLoader>() {
public TransletClassLoader run() {
return new TransletClassLoader(ObjectFactory.findClassLoader(),
_tfactory.getExternalExtensionsMap());
}
});
try {
final int classCount = _bytecodes.length;
_class = new Class<?>[classCount];
if (classCount > 1) {
_auxClasses = new HashMap<>();
}
String mn = "jdk.translet";
String pn = _tfactory.getPackageName();
assert pn != null && pn.length() > 0;
ModuleDescriptor descriptor =
ModuleDescriptor.newModule(mn, Set.of(ModuleDescriptor.Modifier.SYNTHETIC))
.requires("java.xml")
.exports(pn, Set.of("java.xml"))
.build();
Module m = createModule(descriptor, loader);
Module thisModule = TemplatesImpl.class.getModule();
PermissionCollection perms =
new RuntimePermission("*").newPermissionCollection();
Arrays.asList(Constants.PKGS_USED_BY_TRANSLET_CLASSES).forEach(p -> {
thisModule.addExports(p, m);
perms.add(new RuntimePermission("accessClassInPackage." + p));
});
CodeSource codeSource = new CodeSource(null, (CodeSigner[])null);
ProtectionDomain pd = new ProtectionDomain(codeSource, perms,
loader, null);
thisModule.addReads(m);
for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i], pd);
final Class<?> superClass = _class[i].getSuperclass();
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}
if (_transletIndex < 0) {
ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
catch (ClassFormatError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
throw new TransformerConfigurationException(err.toString(), e);
}
catch (LinkageError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString(), e);
}
}
private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null;
if (_class == null) defineTransletClasses();
AbstractTranslet translet = (AbstractTranslet)