001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: TemplatesImpl.java 468653 2006-10-28 07:07:05Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.trax; 023 024 import java.io.IOException; 025 import java.io.ObjectInputStream; 026 import java.io.ObjectOutputStream; 027 import java.io.Serializable; 028 import java.util.Properties; 029 import java.security.AccessController; 030 import java.security.PrivilegedAction; 031 032 import javax.xml.XMLConstants; 033 import javax.xml.transform.Templates; 034 import javax.xml.transform.Transformer; 035 import javax.xml.transform.TransformerConfigurationException; 036 import javax.xml.transform.URIResolver; 037 038 import org.apache.xalan.xsltc.DOM; 039 import org.apache.xalan.xsltc.Translet; 040 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 041 import org.apache.xalan.xsltc.runtime.AbstractTranslet; 042 import org.apache.xalan.xsltc.runtime.Hashtable; 043 044 /** 045 * @author Morten Jorgensen 046 * @author G. Todd Millerj 047 * @author Jochen Cordes <Jochen.Cordes@t-online.de> 048 * @author Santiago Pericas-Geertsen 049 */ 050 public final class TemplatesImpl implements Templates, Serializable { 051 static final long serialVersionUID = 673094361519270707L; 052 /** 053 * Name of the superclass of all translets. This is needed to 054 * determine which, among all classes comprising a translet, 055 * is the main one. 056 */ 057 private static String ABSTRACT_TRANSLET 058 = "org.apache.xalan.xsltc.runtime.AbstractTranslet"; 059 060 /** 061 * Name of the main class or default name if unknown. 062 */ 063 private String _name = null; 064 065 /** 066 * Contains the actual class definition for the translet class and 067 * any auxiliary classes. 068 */ 069 private byte[][] _bytecodes = null; 070 071 /** 072 * Contains the translet class definition(s). These are created when 073 * this Templates is created or when it is read back from disk. 074 */ 075 private Class[] _class = null; 076 077 /** 078 * The index of the main translet class in the arrays _class[] and 079 * _bytecodes. 080 */ 081 private int _transletIndex = -1; 082 083 /** 084 * Contains the list of auxiliary class definitions. 085 */ 086 private Hashtable _auxClasses = null; 087 088 /** 089 * Output properties of this translet. 090 */ 091 private Properties _outputProperties; 092 093 /** 094 * Number of spaces to add for output indentation. 095 */ 096 private int _indentNumber; 097 098 /** 099 * This URIResolver is passed to all Transformers. 100 * Declaring it transient to fix bug 22438 101 */ 102 private transient URIResolver _uriResolver = null; 103 104 /** 105 * Cache the DTM for the stylesheet in a thread local variable, 106 * which is used by the document('') function. 107 * Use ThreadLocal because a DTM cannot be shared between 108 * multiple threads. 109 * Declaring it transient to fix bug 22438 110 */ 111 private transient ThreadLocal _sdom = new ThreadLocal(); 112 113 /** 114 * A reference to the transformer factory that this templates 115 * object belongs to. 116 */ 117 private transient TransformerFactoryImpl _tfactory = null; 118 119 static final class TransletClassLoader extends ClassLoader { 120 TransletClassLoader(ClassLoader parent) { 121 super(parent); 122 } 123 124 /** 125 * Access to final protected superclass member from outer class. 126 */ 127 Class defineClass(final byte[] b) { 128 return defineClass(null, b, 0, b.length); 129 } 130 } 131 132 133 /** 134 * Create an XSLTC template object from the bytecodes. 135 * The bytecodes for the translet and auxiliary classes, plus the name of 136 * the main translet class, must be supplied. 137 */ 138 protected TemplatesImpl(byte[][] bytecodes, String transletName, 139 Properties outputProperties, int indentNumber, 140 TransformerFactoryImpl tfactory) 141 { 142 _bytecodes = bytecodes; 143 _name = transletName; 144 _outputProperties = outputProperties; 145 _indentNumber = indentNumber; 146 _tfactory = tfactory; 147 } 148 149 /** 150 * Create an XSLTC template object from the translet class definition(s). 151 */ 152 protected TemplatesImpl(Class[] transletClasses, String transletName, 153 Properties outputProperties, int indentNumber, 154 TransformerFactoryImpl tfactory) 155 { 156 _class = transletClasses; 157 _name = transletName; 158 _transletIndex = 0; 159 _outputProperties = outputProperties; 160 _indentNumber = indentNumber; 161 _tfactory = tfactory; 162 } 163 164 165 /** 166 * Need for de-serialization, see readObject(). 167 */ 168 public TemplatesImpl() { } 169 170 /** 171 * Overrides the default readObject implementation since we decided 172 * it would be cleaner not to serialize the entire tranformer 173 * factory. [ ref bugzilla 12317 ] 174 * We need to check if the user defined class for URIResolver also 175 * implemented Serializable 176 * if yes then we need to deserialize the URIResolver 177 * Fix for bugzilla bug 22438 178 */ 179 private void readObject(ObjectInputStream is) 180 throws IOException, ClassNotFoundException 181 { 182 is.defaultReadObject(); 183 if (is.readBoolean()) { 184 _uriResolver = (URIResolver) is.readObject(); 185 } 186 187 _tfactory = new TransformerFactoryImpl(); 188 } 189 190 191 /** 192 * This is to fix bugzilla bug 22438 193 * If the user defined class implements URIResolver and Serializable 194 * then we want it to get serialized 195 */ 196 private void writeObject(ObjectOutputStream os) 197 throws IOException, ClassNotFoundException { 198 os.defaultWriteObject(); 199 if (_uriResolver instanceof Serializable) { 200 os.writeBoolean(true); 201 os.writeObject((Serializable) _uriResolver); 202 } 203 else { 204 os.writeBoolean(false); 205 } 206 } 207 208 209 /** 210 * Store URIResolver needed for Transformers. 211 */ 212 public synchronized void setURIResolver(URIResolver resolver) { 213 _uriResolver = resolver; 214 } 215 216 /** 217 * The TransformerFactory must pass us the translet bytecodes using this 218 * method before we can create any translet instances 219 */ 220 protected synchronized void setTransletBytecodes(byte[][] bytecodes) { 221 _bytecodes = bytecodes; 222 } 223 224 /** 225 * Returns the translet bytecodes stored in this template 226 */ 227 public synchronized byte[][] getTransletBytecodes() { 228 return _bytecodes; 229 } 230 231 /** 232 * Returns the translet bytecodes stored in this template 233 */ 234 public synchronized Class[] getTransletClasses() { 235 try { 236 if (_class == null) defineTransletClasses(); 237 } 238 catch (TransformerConfigurationException e) { 239 // Falls through 240 } 241 return _class; 242 } 243 244 /** 245 * Returns the index of the main class in array of bytecodes 246 */ 247 public synchronized int getTransletIndex() { 248 try { 249 if (_class == null) defineTransletClasses(); 250 } 251 catch (TransformerConfigurationException e) { 252 // Falls through 253 } 254 return _transletIndex; 255 } 256 257 /** 258 * The TransformerFactory should call this method to set the translet name 259 */ 260 protected synchronized void setTransletName(String name) { 261 _name = name; 262 } 263 264 /** 265 * Returns the name of the main translet class stored in this template 266 */ 267 protected synchronized String getTransletName() { 268 return _name; 269 } 270 271 /** 272 * Defines the translet class and auxiliary classes. 273 * Returns a reference to the Class object that defines the main class 274 */ 275 private void defineTransletClasses() 276 throws TransformerConfigurationException { 277 278 if (_bytecodes == null) { 279 ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); 280 throw new TransformerConfigurationException(err.toString()); 281 } 282 283 TransletClassLoader loader = (TransletClassLoader) 284 AccessController.doPrivileged(new PrivilegedAction() { 285 public Object run() { 286 return new TransletClassLoader(ObjectFactory.findClassLoader()); 287 } 288 }); 289 290 try { 291 final int classCount = _bytecodes.length; 292 _class = new Class[classCount]; 293 294 if (classCount > 1) { 295 _auxClasses = new Hashtable(); 296 } 297 298 for (int i = 0; i < classCount; i++) { 299 _class[i] = loader.defineClass(_bytecodes[i]); 300 final Class superClass = _class[i].getSuperclass(); 301 302 // Check if this is the main class 303 if (superClass.getName().equals(ABSTRACT_TRANSLET)) { 304 _transletIndex = i; 305 } 306 else { 307 _auxClasses.put(_class[i].getName(), _class[i]); 308 } 309 } 310 311 if (_transletIndex < 0) { 312 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); 313 throw new TransformerConfigurationException(err.toString()); 314 } 315 } 316 catch (ClassFormatError e) { 317 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name); 318 throw new TransformerConfigurationException(err.toString()); 319 } 320 catch (LinkageError e) { 321 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); 322 throw new TransformerConfigurationException(err.toString()); 323 } 324 } 325 326 /** 327 * This method generates an instance of the translet class that is 328 * wrapped inside this Template. The translet instance will later 329 * be wrapped inside a Transformer object. 330 */ 331 private Translet getTransletInstance() 332 throws TransformerConfigurationException { 333 try { 334 if (_name == null) return null; 335 336 if (_class == null) defineTransletClasses(); 337 338 // The translet needs to keep a reference to all its auxiliary 339 // class to prevent the GC from collecting them 340 AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance(); 341 translet.postInitialization(); 342 translet.setTemplates(this); 343 if (_auxClasses != null) { 344 translet.setAuxiliaryClasses(_auxClasses); 345 } 346 347 return translet; 348 } 349 catch (InstantiationException e) { 350 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); 351 throw new TransformerConfigurationException(err.toString()); 352 } 353 catch (IllegalAccessException e) { 354 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); 355 throw new TransformerConfigurationException(err.toString()); 356 } 357 } 358 359 /** 360 * Implements JAXP's Templates.newTransformer() 361 * 362 * @throws TransformerConfigurationException 363 */ 364 public synchronized Transformer newTransformer() 365 throws TransformerConfigurationException 366 { 367 TransformerImpl transformer; 368 369 transformer = new TransformerImpl(getTransletInstance(), _outputProperties, 370 _indentNumber, _tfactory); 371 372 if (_uriResolver != null) { 373 transformer.setURIResolver(_uriResolver); 374 } 375 376 if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) { 377 transformer.setSecureProcessing(true); 378 } 379 return transformer; 380 } 381 382 /** 383 * Implements JAXP's Templates.getOutputProperties(). We need to 384 * instanciate a translet to get the output settings, so 385 * we might as well just instanciate a Transformer and use its 386 * implementation of this method. 387 */ 388 public synchronized Properties getOutputProperties() { 389 try { 390 return newTransformer().getOutputProperties(); 391 } 392 catch (TransformerConfigurationException e) { 393 return null; 394 } 395 } 396 397 /** 398 * Return the thread local copy of the stylesheet DOM. 399 */ 400 public DOM getStylesheetDOM() { 401 return (DOM)_sdom.get(); 402 } 403 404 /** 405 * Set the thread local copy of the stylesheet DOM. 406 */ 407 public void setStylesheetDOM(DOM sdom) { 408 _sdom.set(sdom); 409 } 410 }