1 16 package org.apache.cocoon.components.xslt; 17 18 import java.io.File ; 19 import java.io.IOException ; 20 import java.util.HashMap ; 21 22 import javax.xml.transform.Result ; 23 import javax.xml.transform.Templates ; 24 import javax.xml.transform.Transformer ; 25 import javax.xml.transform.TransformerException ; 26 import javax.xml.transform.TransformerFactory ; 27 import javax.xml.transform.URIResolver ; 28 import javax.xml.transform.sax.SAXTransformerFactory ; 29 import javax.xml.transform.sax.TemplatesHandler ; 30 import javax.xml.transform.sax.TransformerHandler ; 31 import javax.xml.transform.stream.StreamSource ; 32 33 import org.apache.avalon.framework.activity.Disposable; 34 import org.apache.avalon.framework.component.ComponentException; 35 import org.apache.avalon.framework.component.ComponentManager; 36 import org.apache.avalon.framework.component.Composable; 37 import org.apache.avalon.framework.logger.AbstractLogEnabled; 38 import org.apache.avalon.framework.parameters.ParameterException; 39 import org.apache.avalon.framework.parameters.Parameterizable; 40 import org.apache.avalon.framework.parameters.Parameters; 41 import org.apache.cocoon.ProcessingException; 42 import org.apache.cocoon.util.ClassUtils; 43 import org.apache.cocoon.util.TraxErrorHandler; 44 import org.apache.excalibur.source.Source; 45 import org.apache.excalibur.source.SourceException; 46 import org.apache.excalibur.source.SourceResolver; 47 import org.apache.excalibur.store.Store; 48 import org.xml.sax.ContentHandler ; 49 import org.xml.sax.SAXException ; 50 import org.xml.sax.XMLFilter ; 51 52 83 public class XSLTProcessorImpl 84 extends AbstractLogEnabled 85 implements XSLTProcessor, 86 Composable, 87 Disposable, 88 Parameterizable, 89 URIResolver { 90 91 protected ComponentManager manager; 92 93 94 protected Store store; 95 96 97 protected HashMap factories; 98 99 100 protected SAXTransformerFactory factory; 101 102 103 protected boolean useStore = true; 104 105 106 protected boolean incrementalProcessing = false; 107 108 109 protected SourceResolver resolver; 110 111 112 protected TraxErrorHandler errorHandler; 113 114 117 public void compose(ComponentManager manager) 118 throws ComponentException { 119 this.manager = manager; 120 if (this.getLogger().isDebugEnabled()) 121 this.getLogger().debug("XSLTProcessorImpl component initialized."); 122 this.store = (Store) manager.lookup(Store.TRANSIENT_STORE); 123 this.errorHandler = new TraxErrorHandler( this.getLogger() ); 124 this.resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 125 } 126 127 130 public void dispose() { 131 if (this.manager != null) { 132 this.manager.release(this.store); 133 this.store = null; 134 this.manager.release(this.resolver); 135 this.resolver = null; 136 } 137 this.errorHandler = null; 138 this.manager = null; 139 } 140 141 144 public void parameterize(Parameters params) 145 throws ParameterException { 146 this.useStore = params.getParameterAsBoolean("use-store", true); 147 this.incrementalProcessing = params.getParameterAsBoolean("incremental-processing", false); 148 this.factory = getTransformerFactory(params.getParameter("transformer-factory", DEFAULT_FACTORY)); 149 } 150 151 155 public void setSourceResolver(org.apache.cocoon.environment.SourceResolver resolver) { 156 if (this.getLogger().isDebugEnabled()) { 157 this.getLogger().debug("XSLTProcessor: the setSourceResolver() method is deprecated."); 158 } 159 } 160 161 164 public void setTransformerFactory(String classname) { 165 this.factory = getTransformerFactory(classname); 166 } 167 168 public TransformerHandler getTransformerHandler(org.apache.cocoon.environment.Source stylesheet) 169 throws ProcessingException { 170 return getTransformerHandler(stylesheet, null); 171 } 172 173 public TransformerHandler getTransformerHandler(org.apache.cocoon.environment.Source stylesheet, 174 XMLFilter filter) 175 throws ProcessingException { 176 try { 177 final String id = stylesheet.getSystemId(); 178 Templates templates = getTemplates(stylesheet, id); 179 if (templates == null) { 180 if (this.getLogger().isDebugEnabled()) { 181 getLogger().debug("Creating new Templates for " + id); 182 } 183 184 TemplatesHandler templatesHandler = this.factory.newTemplatesHandler(); 187 188 templatesHandler.setSystemId(id); 192 193 if (filter != null) { 194 filter.setContentHandler(templatesHandler); 195 } 196 197 if (this.getLogger().isDebugEnabled()) { 198 getLogger().debug("Source = " + stylesheet 199 + ", templatesHandler = " + templatesHandler); 200 } 201 202 stylesheet.toSAX(filter != null ? 204 (ContentHandler )filter : (ContentHandler )templatesHandler); 205 206 templates = templatesHandler.getTemplates(); 209 putTemplates (templates, stylesheet, id); 210 } else { 211 if (this.getLogger().isDebugEnabled()) { 212 getLogger().debug("Reusing Templates for " + id); 213 } 214 } 215 216 TransformerHandler handler = this.factory.newTransformerHandler(templates); 217 handler.getTransformer().setErrorListener(this.errorHandler); 218 handler.getTransformer().setURIResolver(this); 219 return handler; 220 } catch (ProcessingException e) { 221 throw e; 222 } catch (SAXException e) { 223 if (e.getException() == null) { 224 throw new ProcessingException("Exception in creating Transform Handler", e); 225 } else { 226 if (getLogger().isDebugEnabled()) 227 getLogger().debug("Got SAXException. Rethrowing cause exception.", e); 228 throw new ProcessingException("Exception in creating Transform Handler", e.getException()); 229 } 230 } catch (Exception e) { 231 throw new ProcessingException("Exception in creating Transform Handler", e); 232 } 233 } 234 235 public void transform(org.apache.cocoon.environment.Source source, 236 org.apache.cocoon.environment.Source stylesheet, 237 Parameters params, 238 Result result) 239 throws ProcessingException { 240 try { 241 if (this.getLogger().isDebugEnabled()) { 242 getLogger().debug("XSLTProcessorImpl: transform source = " + source 243 + ", stylesheet = " + stylesheet 244 + ", parameters = " + params 245 + ", result = " + result); 246 } 247 TransformerHandler handler = getTransformerHandler(stylesheet); 248 249 Transformer transformer = handler.getTransformer(); 250 if (params != null) { 251 transformer.clearParameters(); 252 String [] names = params.getNames(); 253 for (int i = names.length -1 ; i >= 0; i--) { 254 transformer.setParameter(names[i], params.getParameter(names[i])); 255 } 256 } 257 258 if (getLogger().isDebugEnabled()) 259 this.getLogger().debug("XSLTProcessorImpl: starting transform"); 260 handler.setResult(result); 262 source.toSAX(handler); 263 264 if (getLogger().isDebugEnabled()) 265 this.getLogger().debug("XSLTProcessorImpl: transform done"); 266 } catch (Exception e) { 267 throw new ProcessingException("Error in running Transformation", e); 268 } 269 } 270 271 276 private SAXTransformerFactory getTransformerFactory(String factoryName) { 277 SAXTransformerFactory _factory; 278 279 if ((factoryName == null) || (factoryName == XSLTProcessor.DEFAULT_FACTORY)) { 280 _factory = (SAXTransformerFactory ) TransformerFactory.newInstance(); 281 } else { 282 try { 283 _factory = (SAXTransformerFactory ) ClassUtils.loadClass(factoryName).newInstance(); 284 } catch (ClassNotFoundException cnfe) { 285 if (getLogger().isErrorEnabled()) 286 getLogger().error("Cannot find the requested TrAX factory '" + factoryName 287 + "'. Using default TrAX Transformer Factory instead."); 288 if (this.factory != null) return this.factory; 289 _factory = (SAXTransformerFactory ) TransformerFactory.newInstance(); 290 } catch (ClassCastException cce) { 291 if (getLogger().isErrorEnabled()) 292 getLogger().error("The indicated class '" + factoryName 293 + "' is not a TrAX Transformer Factory. Using default TrAX Transformer Factory instead."); 294 if (this.factory != null) return this.factory; 295 _factory = (SAXTransformerFactory ) TransformerFactory.newInstance(); 296 } catch (Exception e) { 297 if (getLogger().isErrorEnabled()) 298 getLogger().error("Error found loading the requested TrAX Transformer Factory '" 299 + factoryName + "'. Using default TrAX Transformer Factory instead."); 300 if (this.factory != null) return this.factory; 301 _factory = (SAXTransformerFactory ) TransformerFactory.newInstance(); 302 } 303 } 304 305 _factory.setErrorListener(this.errorHandler); 306 _factory.setURIResolver(this); 307 308 if (_factory.getClass().getName().equals("org.apache.xalan.processor.TransformerFactoryImpl")) { 311 _factory.setAttribute("http://xml.apache.org/xalan/features/incremental", 312 new Boolean (incrementalProcessing)); 313 } 314 315 return _factory; 316 } 317 318 private Templates getTemplates(org.apache.cocoon.environment.Source stylesheet, 319 String id) 320 throws IOException , ProcessingException { 321 if (!useStore) { 322 return null; 323 } 324 325 id += factory.getClass().getName(); 329 330 Templates templates = null; 331 if (stylesheet.getLastModified() != 0) { 333 if (store.containsKey(id)) { 335 Object [] templateAndTime = (Object [])store.get(id); 336 337 if(templateAndTime != null && templateAndTime[1] != null) { 338 long storedTime = ((Long )templateAndTime[1]).longValue(); 339 340 if (storedTime < stylesheet.getLastModified()) { 341 store.remove(id); 342 } else { 343 templates = (Templates )templateAndTime[0]; 344 } 345 } 346 } 347 } else if (store.containsKey(id)) { 348 store.remove(id); 350 } 351 return templates; 352 } 353 354 private void putTemplates (Templates templates, org.apache.cocoon.environment.Source stylesheet, 355 String id) 356 throws IOException , ProcessingException { 357 if (!useStore) { 358 return; 359 } 360 361 id += factory.getClass().getName(); 365 366 if (stylesheet.getLastModified() != 0) { 368 369 Object [] templateAndTime = new Object [2]; 371 templateAndTime[0] = templates; 372 templateAndTime[1] = new Long (stylesheet.getLastModified()); 373 store.store(id, templateAndTime); 374 } 375 } 376 377 391 public javax.xml.transform.Source resolve(String href, String base) 392 throws TransformerException { 393 if (this.getLogger().isDebugEnabled()) { 394 this.getLogger().debug("resolve(href = " + href + 395 ", base = " + base + "); resolver = " + resolver); 396 } 397 398 Source xslSource = null; 399 try { 400 if (href.indexOf(":") > 1) { 401 xslSource = resolver.resolveURI(href); 402 } else { 403 if (base == null) 405 throw new IllegalArgumentException ("Null pointer passed as base"); 406 407 if (!base.startsWith("file:")) { 409 int lastPathElementPos = base.lastIndexOf('/'); 410 if (lastPathElementPos == -1) { 411 return null; } else { 415 xslSource = resolver.resolveURI(new StringBuffer (base.substring(0, lastPathElementPos)) 416 .append("/").append(href).toString()); 417 } 418 } else { 419 File parent = new File (base.substring(5)); 420 File parent2 = new File (parent.getParentFile(), href); 421 xslSource = resolver.resolveURI(parent2.toURL().toExternalForm()); 422 } 423 } 424 425 if (this.getLogger().isDebugEnabled()) { 426 getLogger().debug("xslSource = " + xslSource 427 + ", system id = " + xslSource.getURI()); 428 } 429 430 return new StreamSource (xslSource.getInputStream(), xslSource.getURI()); 431 432 } catch (java.net.MalformedURLException mue) { 433 return null; 434 } catch (SourceException pe) { 435 throw new TransformerException (pe); 436 } catch (IOException ioe) { 437 return null; 438 } finally { 439 this.resolver.release( xslSource ); 440 } 441 } 442 } 443 | Popular Tags |