KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > xsl > AbstractStylesheetFactory


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.xsl;
31
32 import com.caucho.java.JavaCompiler;
33 import com.caucho.loader.DynamicClassLoader;
34 import com.caucho.loader.EnvironmentLocal;
35 import com.caucho.loader.SimpleLoader;
36 import com.caucho.log.Log;
37 import com.caucho.server.util.CauchoSystem;
38 import com.caucho.util.Base64;
39 import com.caucho.util.CharBuffer;
40 import com.caucho.util.L10N;
41 import com.caucho.util.LruCache;
42 import com.caucho.vfs.Crc64Stream;
43 import com.caucho.vfs.Path;
44 import com.caucho.vfs.ReadStream;
45 import com.caucho.vfs.Vfs;
46 import com.caucho.vfs.WriteStream;
47 import com.caucho.xml.*;
48 import com.caucho.xpath.Expr;
49 import com.caucho.xpath.XPath;
50
51 import org.w3c.dom.Attr JavaDoc;
52 import org.w3c.dom.Document JavaDoc;
53 import org.w3c.dom.DocumentType JavaDoc;
54 import org.w3c.dom.Node JavaDoc;
55 import org.xml.sax.ContentHandler JavaDoc;
56 import org.xml.sax.InputSource JavaDoc;
57 import org.xml.sax.XMLFilter JavaDoc;
58 import org.xml.sax.XMLReader JavaDoc;
59
60 import javax.xml.transform.ErrorListener JavaDoc;
61 import javax.xml.transform.Source JavaDoc;
62 import javax.xml.transform.Templates JavaDoc;
63 import javax.xml.transform.TransformerConfigurationException JavaDoc;
64 import javax.xml.transform.TransformerException JavaDoc;
65 import javax.xml.transform.URIResolver JavaDoc;
66 import javax.xml.transform.dom.DOMResult JavaDoc;
67 import javax.xml.transform.dom.DOMSource JavaDoc;
68 import javax.xml.transform.sax.SAXResult JavaDoc;
69 import javax.xml.transform.sax.SAXSource JavaDoc;
70 import javax.xml.transform.sax.SAXTransformerFactory JavaDoc;
71 import javax.xml.transform.sax.TemplatesHandler JavaDoc;
72 import javax.xml.transform.sax.TransformerHandler JavaDoc;
73 import javax.xml.transform.stream.StreamResult JavaDoc;
74 import javax.xml.transform.stream.StreamSource JavaDoc;
75 import java.io.IOException JavaDoc;
76 import java.io.InputStream JavaDoc;
77 import java.io.OutputStream JavaDoc;
78 import java.io.Reader JavaDoc;
79 import java.lang.ref.SoftReference JavaDoc;
80 import java.util.Iterator JavaDoc;
81 import java.util.Random JavaDoc;
82 import java.util.logging.Level JavaDoc;
83 import java.util.logging.Logger JavaDoc;
84
85 /**
86  * Abstract factory for creating stylesheets.
87  */

88 abstract public class AbstractStylesheetFactory
89   extends SAXTransformerFactory JavaDoc {
90   static final Logger JavaDoc log = Log.open(AbstractStylesheetFactory.class);
91   static final L10N L = new L10N(AbstractStylesheetFactory.class);
92
93   private static
94     EnvironmentLocal<LruCache<String JavaDoc,SoftReference JavaDoc<StylesheetImpl>>> _stylesheetCache =
95     new EnvironmentLocal<LruCache<String JavaDoc,SoftReference JavaDoc<StylesheetImpl>>>();
96               
97   private URIResolver JavaDoc _uriResolver;
98   private ErrorListener JavaDoc _errorListener;
99
100   private String JavaDoc _systemId;
101
102   private Path _workPath;
103   private Path _stylePath;
104   private ClassLoader JavaDoc _loader;
105   private String JavaDoc _className;
106   private boolean _isAutoCompile = true;
107   private boolean _loadPrecompiledStylesheet = true;
108
109   protected AbstractStylesheetFactory()
110   {
111   }
112
113   /**
114    * Returns an implementation-specific attribute.
115    *
116    * @param name the attribute name
117    */

118   public Object JavaDoc getAttribute(String JavaDoc name)
119   {
120     return null;
121   }
122
123   /**
124    * Sets an implementation-specific attribute.
125    *
126    * @param name the attribute name
127    * @param value the attribute value
128    */

129   public void setAttribute(String JavaDoc name, Object JavaDoc value)
130   {
131   }
132
133   /**
134    * Returns an implementation-specific feature.
135    *
136    * @param name the feature name
137    */

138   public boolean getFeature(String JavaDoc name)
139   {
140     if (name.equals(SAXTransformerFactory.FEATURE) ||
141         name.equals(SAXTransformerFactory.FEATURE_XMLFILTER) ||
142         name.equals(DOMResult.FEATURE) ||
143         name.equals(DOMSource.FEATURE) ||
144         name.equals(SAXResult.FEATURE) ||
145         name.equals(SAXSource.FEATURE) ||
146         name.equals(StreamResult.FEATURE) ||
147         name.equals(StreamSource.FEATURE))
148       return true;
149     else
150       return false;
151   }
152
153   /**
154    * Sets an implementation-specific feature
155    *
156    * @param name the feature name
157    * @param value the feature value
158    */

159   public void setFeature(String JavaDoc name, boolean value)
160   {
161   }
162
163   /**
164    * Returns the URI to filename resolver.
165    */

166   public URIResolver JavaDoc getURIResolver()
167   {
168     return _uriResolver;
169   }
170
171   /**
172    * Sets the URI to filename resolver.
173    */

174   public void setURIResolver(URIResolver JavaDoc uriResolver)
175   {
176     _uriResolver = uriResolver;
177   }
178
179   /**
180    * Returns the error listener.
181    */

182   public ErrorListener JavaDoc getErrorListener()
183   {
184     return _errorListener;
185   }
186
187   /**
188    * Sets the error listener.
189    */

190   public void setErrorListener(ErrorListener JavaDoc errorListener)
191   {
192     _errorListener = errorListener;
193   }
194
195   public String JavaDoc getSystemId()
196   {
197     return _systemId;
198   }
199
200   public void setSystemId(String JavaDoc systemId)
201   {
202     _systemId = systemId;
203   }
204
205   /**
206    * Sets the search path for stylesheets. Generally applications will use
207    * MergePath to create their search path.
208    *
209    * @param path path containing stylesheets.
210    */

211   public void setStylePath(Path path)
212   {
213     _stylePath = path;
214   }
215
216   /**
217    * Returns the stylesheet search path.
218    */

219   public Path getStylePath()
220   {
221     if (_stylePath != null)
222       return _stylePath;
223     else
224       return getSearchPath();
225   }
226
227   /**
228    * Sets the search path for stylesheets. Generally applications will use
229    * MergePath to create their search path.
230    *
231    * @param path path containing stylesheets.
232    */

233   public void setSearchPath(Path path)
234   {
235     _stylePath = path;
236   }
237
238   /**
239    * Returns the stylesheet search path.
240    */

241   public Path getSearchPath()
242   {
243     if (_stylePath != null)
244       return _stylePath;
245     else
246       return Vfs.getPwd();
247   }
248
249   /**
250    * Sets the working directory.
251    */

252   public void setWorkPath(Path path)
253   {
254     _workPath = path;
255   }
256
257   /**
258    * Gets the working directory.
259    */

260   public Path getWorkPath()
261   {
262     if (_workPath != null)
263       return _workPath;
264     else
265       return CauchoSystem.getWorkPath();
266   }
267
268   public void setClassName(String JavaDoc className)
269   {
270     _className = className;
271   }
272
273   public String JavaDoc getClassName()
274   {
275     return _className;
276   }
277
278   /**
279    * Sets the classloader for the stylesheet.
280    *
281    * @param loader the new loader.
282    */

283   public void setClassLoader(ClassLoader JavaDoc loader)
284   {
285     _loader = loader;
286   }
287
288   /**
289    * Gets the classloader for the stylesheet.
290    */

291   public ClassLoader JavaDoc getClassLoader()
292   {
293     return _loader;
294   }
295
296   /**
297    * Returns true if precompiled stylesheets should be loaded.
298    */

299   public boolean getLoadPrecompiledStylesheet()
300   {
301     return _loadPrecompiledStylesheet;
302   }
303
304   /**
305    * Returns true if precompiled stylesheets should be loaded.
306    */

307   public void setLoadPrecompiledStylesheet(boolean preload)
308   {
309     _loadPrecompiledStylesheet = preload;
310   }
311
312   /**
313    * Returns true if the stylesheet should be automatically compiled.
314    */

315   public boolean isAutoCompile()
316   {
317     return _isAutoCompile;
318   }
319
320   /**
321    * Returns true if precompiled stylesheets should be loaded.
322    */

323   public void setAutoCompile(boolean autoCompile)
324   {
325     _isAutoCompile = autoCompile;
326   }
327
328   /**
329    * Returns the stylesheet source object associated with the given
330    * XML document.
331    *
332    * @param source the XML document which needs a stylesheet.
333    * @param media the media attribute for the stylesheet
334    * @param title the title attribute for the stylesheet
335    * @param charset the character encoding for the stylesheet result.
336    */

337   public Source JavaDoc getAssociatedStylesheet(Source JavaDoc source,
338                                         String JavaDoc media,
339                                         String JavaDoc title,
340                                         String JavaDoc charset)
341     throws TransformerConfigurationException JavaDoc
342   {
343     try {
344       XmlStylesheetReader reader = new XmlStylesheetReader();
345
346       parseSAX(source, reader);
347
348       String JavaDoc href = reader.getAssociatedStylesheet(media, title, charset);
349
350       if (href == null)
351         return null;
352
353       String JavaDoc base = source.getSystemId();
354     
355       return getSource(href, base);
356     } catch (Exception JavaDoc e) {
357       throw new TransformerConfigurationException JavaDoc(e);
358     }
359   }
360   
361   /**
362    * Opens a relative path.
363    */

364   private Source JavaDoc getSource(String JavaDoc href, String JavaDoc base)
365     throws Exception JavaDoc
366   {
367     Path subpath;
368
369     if (href == null)
370       href = "";
371     if (base == null)
372       base = "/";
373     
374     if (_uriResolver != null) {
375       if (href.startsWith("/") || base.equals("/"))
376         subpath = getSearchPath().lookup(href);
377       else {
378         subpath = getSearchPath().lookup(base).getParent().lookup(href);
379       }
380       
381       Source JavaDoc source = _uriResolver.resolve(href, base);
382
383       if (source != null) {
384         if (source.getSystemId() == null)
385           source.setSystemId(subpath.getURL());
386
387         return source;
388       }
389     }
390     
391     if (href.startsWith("/") || base.equals("/"))
392       subpath = getSearchPath().lookup(href);
393     else {
394       if (base.startsWith("file:"))
395         base = base.substring(5);
396       
397       subpath = getSearchPath().lookup(base).getParent().lookup(href);
398     }
399
400     return new StreamSource JavaDoc(subpath.getURL());
401   }
402
403   private void parseSAX(Source JavaDoc source, ContentHandler JavaDoc handler)
404     throws TransformerConfigurationException JavaDoc
405   {
406     try {
407       if (source instanceof SAXSource JavaDoc) {
408         SAXSource JavaDoc saxSource = (SAXSource JavaDoc) source;
409
410         XMLReader JavaDoc reader = saxSource.getXMLReader();
411         InputSource JavaDoc inputSource = saxSource.getInputSource();
412
413         reader.setContentHandler(handler);
414
415         reader.parse(inputSource);
416       }
417       else if (source instanceof StreamSource JavaDoc) {
418
419         XmlParser parser = new Xml();
420
421         parser.setContentHandler(handler);
422
423         ReadStream rs = openPath(source);
424         try {
425           parser.parse(rs);
426         } finally {
427           rs.close();
428         }
429       }
430       else if (source instanceof DOMSource JavaDoc) {
431         DOMSource JavaDoc domSource = (DOMSource JavaDoc) source;
432
433         Node JavaDoc node = domSource.getNode();
434
435         XmlUtil.toSAX(node, handler);
436       }
437     } catch (Exception JavaDoc e) {
438       throw new TransformerConfigurationException JavaDoc(e);
439     }
440   }
441
442   /**
443    * Create a transformer from an input stream.
444    *
445    * @param source the source stream
446    *
447    * @return the compiled stylesheet
448    */

449   public javax.xml.transform.Transformer JavaDoc newTransformer(Source JavaDoc source)
450     throws TransformerConfigurationException JavaDoc
451   {
452     Templates JavaDoc templates = newTemplates(source);
453
454     return templates.newTransformer();
455   }
456
457   /**
458    * Create an identity transformer.
459    *
460    * @return the compiled stylesheet
461    */

462   public javax.xml.transform.Transformer JavaDoc newTransformer()
463     throws TransformerConfigurationException JavaDoc
464   {
465     return new TransformerImpl(new IdentityStylesheet());
466   }
467
468   /**
469    * Creates a new stylesheet from an XML document.
470    */

471   public StylesheetImpl newStylesheet(Document JavaDoc xsl)
472     throws Exception JavaDoc
473   {
474     return (StylesheetImpl) generate(xsl, null);
475   }
476
477   /**
478    * Create a new stylesheet from a reader.
479    */

480   public StylesheetImpl newStylesheet(Reader JavaDoc reader)
481     throws Exception JavaDoc
482   {
483     ReadStream rs = Vfs.openRead(reader);
484
485     return (StylesheetImpl) generate(parseXSL(rs), rs.getPath());
486   }
487
488   /**
489    * Create a new stylesheet from an input stream.
490    */

491   public StylesheetImpl newStylesheet(InputStream JavaDoc is)
492     throws Exception JavaDoc
493   {
494     ReadStream rs = Vfs.openRead(is);
495
496     return (StylesheetImpl) generate(parseXSL(rs), rs.getPath());
497   }
498
499   /**
500    * Loads a stylesheet from a named file
501    *
502    * @param systemId the URL of the file
503    */

504   public StylesheetImpl newStylesheet(String JavaDoc systemId)
505     throws Exception JavaDoc
506   {
507     StylesheetImpl stylesheet = loadPrecompiledStylesheet(systemId, systemId);
508
509     if (stylesheet != null)
510       return stylesheet;
511
512     synchronized (AbstractStylesheetFactory.class) {
513       stylesheet = loadPrecompiledStylesheet(systemId, systemId);
514
515       if (stylesheet != null)
516     return stylesheet;
517       
518       ReadStream is;
519
520       if (_stylePath != null)
521     is = _stylePath.lookup(systemId).openRead();
522       else
523     is = Vfs.lookup(systemId).openRead();
524     
525       try {
526     return newStylesheet(is);
527       } finally {
528     if (is != null)
529       is.close();
530       }
531     }
532   }
533
534   public StylesheetImpl newStylesheet(Path path)
535     throws Exception JavaDoc
536   {
537     StylesheetImpl stylesheet = loadPrecompiledStylesheet(path.getFullPath(),
538                                                           path.getUserPath());
539
540     if (stylesheet != null)
541       return stylesheet;
542
543     synchronized (AbstractStylesheetFactory.class) {
544       stylesheet = loadPrecompiledStylesheet(path.getFullPath(),
545                          path.getUserPath());
546
547       if (stylesheet != null)
548     return stylesheet;
549     
550       Path oldStylePath = _stylePath;
551     
552       if (_stylePath == null)
553     _stylePath = path.getParent();
554     
555       InputStream JavaDoc is = null;
556     
557       try {
558     is = path.openRead();
559     return newStylesheet(is);
560       } finally {
561     _stylePath = oldStylePath;
562     if (is != null)
563       is.close();
564       }
565     }
566   }
567
568   /**
569    * Create a compiled stylesheet from an input stream.
570    *
571    * @param source the source stream
572    *
573    * @return the compiled stylesheet
574    */

575   public Templates JavaDoc newTemplates(Source JavaDoc source)
576     throws TransformerConfigurationException JavaDoc
577   {
578     String JavaDoc systemId = source.getSystemId();
579
580     try {
581       if (systemId != null) {
582         StylesheetImpl stylesheet = loadPrecompiledStylesheet(systemId,
583                                                               systemId);
584
585         if (stylesheet != null)
586           return stylesheet;
587       }
588
589       if (source instanceof DOMSource JavaDoc) {
590         Node JavaDoc node = ((DOMSource JavaDoc) source).getNode();
591
592     return generateFromNode(node, systemId);
593       }
594       else if (source instanceof SAXSource JavaDoc) {
595         SAXSource JavaDoc saxSource = (SAXSource JavaDoc) source;
596         XMLReader JavaDoc reader = saxSource.getXMLReader();
597         InputSource JavaDoc inputSource = saxSource.getInputSource();
598
599         Document JavaDoc doc = new QDocument();
600         DOMBuilder builder = new DOMBuilder();
601         builder.init(doc);
602         reader.setContentHandler(builder);
603
604         reader.parse(inputSource);
605       
606     return generateFromNode(doc, systemId);
607       }
608
609       ReadStream rs = openPath(source);
610       try {
611         Path path = rs.getPath();
612
613     Document JavaDoc doc = parseXSL(rs);
614
615     if (systemId != null) {
616       String JavaDoc mangledName = getMangledName(systemId);
617       Path genPath = getWorkPath().lookup(mangledName);
618
619       genPath.setUserPath(systemId);
620       
621       return generate(doc, genPath);
622     }
623     else
624       return generateFromNode(doc, null);
625       } finally {
626         if (rs != null)
627           rs.close();
628       }
629     } catch (TransformerConfigurationException JavaDoc e) {
630       throw e;
631     } catch (Exception JavaDoc e) {
632       throw new XslParseException(e);
633     }
634   }
635
636   private Templates JavaDoc generateFromNode(Node JavaDoc node, String JavaDoc systemId)
637     throws IOException JavaDoc, TransformerConfigurationException JavaDoc
638   {
639     Path tempPath = writeTempFile(node);
640
641     String JavaDoc tempId = tempPath.getTail();
642     
643     StylesheetImpl stylesheet = loadPrecompiledStylesheet(tempId,
644                               tempId,
645                               false);
646
647     if (systemId != null)
648       tempPath.setUserPath(systemId);
649
650     if (stylesheet != null)
651       return stylesheet;
652     
653     return generate(node, tempPath);
654   }
655
656   private Path writeTempFile(Node JavaDoc node)
657     throws IOException JavaDoc
658   {
659     Path workDir = CauchoSystem.getWorkPath().lookup("_xsl");
660     workDir.mkdirs();
661     
662     // Path temp = workDir.createTempFile("tmp", "xsl");
663

664     WriteStream os = Vfs.lookup("null:").openWrite();
665     Crc64Stream crcStream = new Crc64Stream(os.getSource());
666     os.init(crcStream);
667     try {
668       XmlPrinter printer = new XmlPrinter(os);
669
670       printer.printNode(node);
671     } finally {
672       os.close();
673     }
674
675     long crc = crcStream.getCRC();
676     CharBuffer cb = new CharBuffer();
677     Base64.encode(cb, crc);
678
679     String JavaDoc crcValue = cb.toString().replace('/', '-');
680
681     Path xslPath = workDir.lookup(crcValue + ".xsl");
682
683     // temp.renameTo(xslPath);
684

685     return xslPath;
686   }
687   
688   /**
689    * Create a new transformer handler.
690    */

691   public TransformerHandler JavaDoc newTransformerHandler()
692     throws TransformerConfigurationException JavaDoc
693   {
694     return newTransformerHandler(new StylesheetImpl());
695   }
696   
697   /**
698    * Create a new transformer handler based on a source.
699    */

700   public TransformerHandler JavaDoc newTransformerHandler(Source JavaDoc source)
701     throws TransformerConfigurationException JavaDoc
702   {
703     return newTransformerHandler(newTemplates(source));
704   }
705   
706   /**
707    * Create a new transformer handler based on a stylesheet.
708    */

709   public TransformerHandler JavaDoc newTransformerHandler(Templates JavaDoc templates)
710     throws TransformerConfigurationException JavaDoc
711   {
712     return new TransformerHandlerImpl(templates.newTransformer());
713   }
714   
715   /**
716    * Returns a templates handler.
717    *
718    * @param source the source file
719    */

720   public TemplatesHandler JavaDoc newTemplatesHandler()
721     throws TransformerConfigurationException JavaDoc
722   {
723     return new TemplatesHandlerImpl(this);
724   }
725   
726   /**
727    * Returns an XML filter from the transformer.
728    *
729    * @param source the source file
730    */

731   public XMLFilter JavaDoc newXMLFilter(Source JavaDoc source)
732     throws TransformerConfigurationException JavaDoc
733   {
734     Templates JavaDoc templates = newTemplates(source);
735     
736     return newXMLFilter(templates);
737   }
738   
739   /**
740    * Returns an XML filter from the transformer.
741    *
742    * @param source the source file
743    */

744   public XMLFilter JavaDoc newXMLFilter(Templates JavaDoc templates)
745     throws TransformerConfigurationException JavaDoc
746   {
747     return new SAXFilterImpl((TransformerImpl) templates.newTransformer());
748   }
749
750   /**
751    * Parses a stylesheet from the source.
752    */

753   protected Node JavaDoc parseStylesheet(Source JavaDoc source)
754     throws TransformerConfigurationException JavaDoc
755   {
756     if (source instanceof DOMSource JavaDoc)
757       return ((DOMSource JavaDoc) source).getNode();
758     else if (source instanceof StreamSource JavaDoc) {
759       InputStream JavaDoc is = ((StreamSource JavaDoc) source).getInputStream();
760       ReadStream rs = null;
761
762       try {
763         rs = Vfs.openRead(is);
764         return parseXSL(rs);
765       } catch (Exception JavaDoc e) {
766         throw new TransformerConfigurationException JavaDoc(e);
767       } finally {
768         if (rs != null)
769           rs.close();
770       }
771     }
772     else
773       return null;
774   }
775
776   /**
777    * Convenience class to create a compiled stylesheet.
778    *
779    * @param node DOM source for the stylesheet.
780    *
781    * @return a compiled stylesheet
782    */

783   public javax.xml.transform.Templates JavaDoc newTemplates(Node JavaDoc node)
784     throws TransformerConfigurationException JavaDoc
785   {
786     Document JavaDoc doc = node.getOwnerDocument();
787     if (node instanceof Document JavaDoc)
788       doc = (Document JavaDoc) node;
789     
790     DocumentType JavaDoc dtd = doc.getDoctype();
791     
792     if (dtd != null && dtd.getSystemId() != null)
793       return generate(node, getSearchPath().lookup(dtd.getSystemId()));
794     else if (doc instanceof CauchoDocument) {
795       String JavaDoc systemId = ((CauchoDocument) doc).getFilename();
796     
797       return generate(node, getSearchPath().lookup(systemId));
798     }
799     else
800       return generate(node, null);
801   }
802
803   /**
804    * Convenience class to create a compiled stylesheet.
805    *
806    * @param systemId source path for the stylesheet.
807    *
808    * @return a compiled stylesheet
809    */

810   public javax.xml.transform.Templates JavaDoc newTemplates(String JavaDoc systemId)
811     throws TransformerConfigurationException JavaDoc
812   {
813     StylesheetImpl stylesheet = loadPrecompiledStylesheet(systemId, systemId);
814
815     if (stylesheet != null)
816       return stylesheet;
817
818     else if (systemId == null)
819       return generate(new QDocument(), null);
820
821     Path path = getSearchPath().lookup(systemId);
822     
823     try {
824       ReadStream is = path.openRead();
825       Document JavaDoc doc;
826       try {
827     doc = parseXSL(is);
828       } finally {
829     is.close();
830       }
831
832       return generate(doc, path);
833     } catch (TransformerConfigurationException JavaDoc e) {
834       throw e;
835     } catch (Exception JavaDoc e) {
836       throw new TransformerConfigurationExceptionWrapper(e);
837     }
838   }
839
840   
841
842   /**
843    * Opens a relative path.
844    */

845   ReadStream openPath(String JavaDoc href, String JavaDoc base)
846     throws TransformerException JavaDoc, IOException JavaDoc
847   {
848     if (_uriResolver != null) {
849       Source JavaDoc source = _uriResolver.resolve(href, base);
850
851       if (source != null)
852         return openPath(source);
853     }
854
855     if (href.startsWith("/") || base.equals("/"))
856       return getSearchPath().lookup(href).openRead();
857     else {
858       Path path = getSearchPath().lookup(base).getParent().lookup(href);
859
860       if (path.exists())
861         return path.openRead();
862       else
863         return getSearchPath().lookup(href).openRead();
864     }
865   }
866
867   /**
868    * Opens a path based on a Source.
869    */

870   ReadStream openPath(Source JavaDoc source)
871     throws TransformerException JavaDoc, IOException JavaDoc
872   {
873     String JavaDoc systemId = source.getSystemId();
874     
875     Path path;
876     if (systemId != null)
877       path = getSearchPath().lookup(systemId);
878     else
879       path = getSearchPath().lookup("anonymous.xsl");
880
881     if (source instanceof StreamSource JavaDoc) {
882       StreamSource JavaDoc stream = (StreamSource JavaDoc) source;
883
884       InputStream JavaDoc is = stream.getInputStream();
885
886       if (is instanceof ReadStream) {
887     ReadStream rs = (ReadStream) is;
888     
889     rs.setPath(path);
890     
891         return rs;
892       }
893       else if (is != null) {
894         ReadStream rs = Vfs.openRead(is);
895         rs.setPath(path);
896
897         return rs;
898       }
899
900       Reader JavaDoc reader = stream.getReader();
901
902       if (reader != null) {
903         ReadStream rs = Vfs.openRead(reader);
904         rs.setPath(path);
905
906         return rs;
907       }
908     }
909     
910     if (systemId != null)
911       return getSearchPath().lookup(systemId).openRead();
912
913     throw new TransformerException JavaDoc("bad source " + source);
914   }
915
916   Path lookupPath(String JavaDoc base, String JavaDoc href)
917     throws TransformerException JavaDoc
918   {
919     if (_uriResolver != null) {
920       Source JavaDoc source = _uriResolver.resolve(href, base);
921
922       if (source != null) {
923         String JavaDoc systemId = source.getSystemId();
924
925         if (systemId != null)
926           return getSearchPath().lookup(systemId);
927       }
928     }
929     
930     return getSearchPath().lookup(base).lookup(href);
931   }
932
933   /**
934    * Convenience class to create a transformer instance.
935    *
936    * @param xsl DOM source for the stylesheet.
937    *
938    * @return a transformer instance.
939    */

940   public javax.xml.transform.Transformer JavaDoc newTransformer(Document JavaDoc xsl)
941     throws TransformerConfigurationException JavaDoc
942   {
943     return newTemplates(xsl).newTransformer();
944   }
945
946   /**
947    * Convenience class to transform a node.
948    *
949    * @param xsl DOM containing the parsed xsl.
950    * @param xml DOM document node.
951    * @param out output stream destination.
952    */

953   public void transform(Document JavaDoc xsl, Node JavaDoc xml, OutputStream JavaDoc out)
954     throws Exception JavaDoc
955   {
956     TransformerImpl transformer = (TransformerImpl) newTransformer(xsl);
957
958     transformer.transform(xml, out);
959   }
960   
961   /**
962    * Convenience class to transform a node.
963    *
964    * @param xsl path name to the xsl file.
965    * @param xml dom source document.
966    * @param out output stream destination.
967    */

968   public void transform(String JavaDoc xsl, Node JavaDoc xml, OutputStream JavaDoc out)
969     throws Exception JavaDoc
970   {
971     TransformerImpl transformer;
972
973     transformer = (TransformerImpl) newTemplates(xsl).newTransformer();
974
975     transformer.transform(xml, out);
976   }
977
978   /**
979    * Parses the XSL into a DOM document.
980    *
981    * @param rs the input stream.
982    */

983   abstract protected Document JavaDoc parseXSL(ReadStream rs)
984     throws TransformerConfigurationException JavaDoc;
985
986   /**
987    * Generates a compiled stylesheet from a parsed XSL document.
988    *
989    * @param xsl the parsed xsl document.
990    * @param path the path to the document.
991    */

992   Templates JavaDoc generate(Node JavaDoc xsl, Path path)
993     throws TransformerConfigurationException JavaDoc
994   {
995     log.fine("Generating XSL from " + path);
996     
997     // The code generation needs a static lock because the
998
// application might have a separate factory object
999
// for each thread. The static lock protects the code generation
1000
// from overwriting its own code.
1001
synchronized (AbstractStylesheetFactory.class) {
1002      Generator gen = null;
1003    
1004      try {
1005        if (path == null && xsl != null) {
1006          Document JavaDoc doc = xsl.getOwnerDocument();
1007          if (doc == null && xsl instanceof Document JavaDoc)
1008            doc = (Document JavaDoc) xsl;
1009
1010          DocumentType JavaDoc dtd = doc.getDoctype();
1011          String JavaDoc systemId = null;
1012          if (dtd != null)
1013            systemId = dtd.getSystemId();
1014
1015          if (systemId != null)
1016            path = getStylePath().lookup(systemId);
1017        }
1018      
1019        if (path == null && xsl instanceof CauchoNode) {
1020          String JavaDoc filename = ((CauchoNode) xsl).getFilename();
1021          if (filename != null)
1022            path = getStylePath().lookup(filename);
1023        }
1024
1025        if (path == null)
1026          path = getStylePath().lookup("anonymous.xsl");
1027
1028        Path stylePath = path.getParent();
1029      
1030        Expr expr = XPath.parseExpr("//xtp:directive.page/@language");
1031        String JavaDoc language = expr.evalString(xsl);
1032
1033        String JavaDoc userName = path.getUserPath();
1034        String JavaDoc mangledName = getMangledName(userName);
1035      
1036        String JavaDoc encoding = XPath.evalString("//xsl:output/@encoding", xsl);
1037        if (encoding != null && encoding.equals(""))
1038          encoding = null;
1039
1040        if (language == null || language.equals("") || language.equals("java")) {
1041          language = "java";
1042          gen = new JavaGenerator(this, mangledName, encoding);
1043        }
1044        else
1045          throw new XslParseException(L.l("unsupported language `{0}'",
1046                                          language));
1047
1048        gen.setPath(path);
1049
1050        Iterator JavaDoc iter = XPath.select("//xtp:directive.page/@*", xsl);
1051        while (iter.hasNext()) {
1052          Attr JavaDoc attr = (Attr JavaDoc) iter.next();
1053          String JavaDoc name = attr.getNodeName();
1054          String JavaDoc value = attr.getNodeValue();
1055    
1056          if (name.equals("errorPage"))
1057            gen.setErrorPage(value);
1058          else if (name.equals("import"))
1059            gen.addImport(value);
1060          else if (name.equals("contentType"))
1061            gen.setContentType(value);
1062          else if (name.equals("language")) {
1063            if (! language.equalsIgnoreCase(value))
1064              throw new XslParseException(L.l("mismatched language `{0}'",
1065                                              value));
1066          }
1067          else if (name.equals("xml:space")) {
1068          }
1069          else
1070            throw new XslParseException(L.l("unknown directive `{0}'",
1071                                            name));
1072        }
1073
1074        StylesheetImpl stylesheet = gen.generate(xsl);
1075        gen = null;
1076        stylesheet.init(path);
1077        // XXX: why was this here? stylesheet.init(getStylePath());
1078
stylesheet.setURIResolver(_uriResolver);
1079
1080        return stylesheet;
1081      } catch (TransformerConfigurationException JavaDoc e) {
1082        throw e;
1083      } catch (Exception JavaDoc e) {
1084        throw new XslParseException(e);
1085      } finally {
1086        try {
1087          if (gen != null)
1088            gen.close();
1089        } catch (IOException JavaDoc e) {
1090        }
1091      }
1092    }
1093  }
1094
1095  /**
1096   * Returns the mangled classname for the stylesheet. If getClassName()
1097   * is not null, it will be used as the mangled name.
1098   *
1099   * @param userName the user specified name for the stylesheet.
1100   *
1101   * @return a valid Java classname for the generated stylesheet.
1102   */

1103  private String JavaDoc getMangledName(String JavaDoc userName)
1104  {
1105    String JavaDoc name = null;
1106
1107    if (userName == null || userName.equals("anonymous.xsl") ||
1108        userName.equals("string") || userName.equals("stream")) {
1109      userName = "x" + (new Random JavaDoc().nextInt() & 0x3ff) + ".xsl";
1110    }
1111    
1112    if (getClassName() == null)
1113      name = userName;
1114    else
1115      name = getClassName();
1116
1117    if (name.startsWith("/"))
1118      name = "xsl" + name;
1119    else
1120      name = "xsl/" + name;
1121    
1122    return JavaCompiler.mangleName(name);
1123  }
1124  
1125  /**
1126   * Returns existing compiled Templates if it exists.
1127   *
1128   * @param systemId source path for the stylesheet.
1129   *
1130   * @return a compiled stylesheet
1131   */

1132  StylesheetImpl loadPrecompiledStylesheet(String JavaDoc systemId,
1133                       String JavaDoc userId)
1134  {
1135    return loadPrecompiledStylesheet(systemId, userId, _isAutoCompile);
1136  }
1137  
1138  /**
1139   * Returns existing compiled Templates if it exists.
1140   *
1141   * @param systemId source path for the stylesheet.
1142   *
1143   * @return a compiled stylesheet
1144   */

1145  StylesheetImpl loadPrecompiledStylesheet(String JavaDoc systemId,
1146                       String JavaDoc userId,
1147                       boolean checkModified)
1148  {
1149    if (! _loadPrecompiledStylesheet)
1150      return null;
1151
1152    try {
1153      // look for compiled template base on SystemID
1154
StylesheetImpl stylesheet = loadStylesheet(systemId,
1155                         getMangledName(userId));
1156
1157      if (stylesheet == null)
1158    return null;
1159      
1160      stylesheet.setURIResolver(_uriResolver);
1161      // and check if it's modified or not
1162
if (! checkModified || ! stylesheet.isModified()) {
1163    stylesheet.setURIResolver(_uriResolver);
1164    return stylesheet;
1165      }
1166    } catch (Throwable JavaDoc e) {
1167      log.log(Level.FINER, e.toString(), e);
1168    }
1169    
1170    return null;
1171  }
1172
1173  /**
1174   * Loads the compiled stylesheet .class file
1175   *
1176   * @param className the mangled classname for the stylesheet
1177   */

1178  protected StylesheetImpl loadStylesheet(String JavaDoc systemId, String JavaDoc className)
1179    throws Exception JavaDoc
1180  {
1181    LruCache<String JavaDoc,SoftReference JavaDoc<StylesheetImpl>> cache;
1182
1183    ClassLoader JavaDoc parentLoader = Thread.currentThread().getContextClassLoader();
1184
1185    cache = _stylesheetCache.getLevel(parentLoader);
1186    
1187    if (cache == null) {
1188      cache = new LruCache<String JavaDoc,SoftReference JavaDoc<StylesheetImpl>>(256);
1189      _stylesheetCache.set(cache, parentLoader);
1190    }
1191
1192    SoftReference JavaDoc<StylesheetImpl> stylesheetRef;
1193
1194    stylesheetRef = cache.get(className);
1195
1196    StylesheetImpl stylesheet = null;
1197
1198    if (stylesheetRef != null)
1199      stylesheet = stylesheetRef.get();
1200
1201    try {
1202      if (stylesheet != null && ! stylesheet.isModified())
1203    return stylesheet;
1204    } catch (Throwable JavaDoc e) {
1205      log.log(Level.FINER, e.toString(), e);
1206    }
1207
1208    Path classPath = getWorkPath().lookup(className.replace('.', '/') + ".class");
1209    if (! classPath.canRead())
1210      throw new ClassNotFoundException JavaDoc("can't find compiled XSL `" + className + "'");
1211
1212    DynamicClassLoader loader;
1213    loader = SimpleLoader.create(parentLoader, getWorkPath(), className);
1214
1215    Class JavaDoc cl = null;
1216
1217    // If the loading fails, remove the class because it may be corrupted
1218
try {
1219      cl = CauchoSystem.loadClass(className, false, loader);
1220    } catch (Error JavaDoc e) {
1221      try {
1222    classPath.remove();
1223      } catch (IOException JavaDoc e1) {
1224        log.log(Level.FINE, e1.toString(), e1);
1225      }
1226      
1227      throw e;
1228    }
1229
1230    stylesheet = (StylesheetImpl) cl.newInstance();
1231    Path path;
1232
1233      path = getSearchPath().lookup("").lookup(systemId);
1234      /*
1235    try {
1236    } catch (TransformerException e) {
1237      log.log(Level.FINE, e.toString(), e);
1238      
1239      path = Vfs.lookup(systemId);
1240    }
1241      */

1242
1243    // stylesheet.init(path);
1244
stylesheet.init(getStylePath());
1245    stylesheet.setURIResolver(_uriResolver);
1246
1247    stylesheetRef = new SoftReference JavaDoc<StylesheetImpl>(stylesheet);
1248    cache.put(className, stylesheetRef);
1249
1250    return stylesheet;
1251  }
1252}
1253
1254
Popular Tags