KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > client > XSLTProcessorApplet


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: XSLTProcessorApplet.java,v 1.6 2007/04/03 21:21:21 joehw Exp $
18  */

19 package com.sun.org.apache.xalan.internal.client;
20
21 import java.applet.Applet JavaDoc;
22 import java.awt.Graphics JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.PrintWriter JavaDoc;
25 import java.io.StringReader JavaDoc;
26 import java.io.StringWriter JavaDoc;
27 import java.net.MalformedURLException JavaDoc;
28 import java.net.URL JavaDoc;
29 import java.util.Hashtable JavaDoc;
30 import java.util.Enumeration JavaDoc;
31
32 import javax.xml.transform.Templates JavaDoc;
33 import javax.xml.transform.Transformer JavaDoc;
34 import javax.xml.transform.TransformerConfigurationException JavaDoc;
35 import javax.xml.transform.TransformerException JavaDoc;
36 import javax.xml.transform.TransformerFactory JavaDoc;
37 import javax.xml.transform.stream.StreamResult JavaDoc;
38 import javax.xml.transform.stream.StreamSource JavaDoc;
39
40 import com.sun.org.apache.xalan.internal.res.XSLMessages;
41 import com.sun.org.apache.xalan.internal.res.XSLTErrorResources;
42
43 /**
44  * Provides applet host for the XSLT processor. To perform transformations on an HTML client:
45  * <ol>
46  * <li>Use an &lt;applet&gt; tag to embed this applet in the HTML client.</li>
47  * <li>Use the DocumentURL and StyleURL PARAM tags or the {@link #setDocumentURL} and
48  * {@link #setStyleURL} methods to specify the XML source document and XSL stylesheet.</li>
49  * <li>Call the {@link #getHtmlText} method (or one of the transformToHtml() methods)
50  * to perform the transformation and return the result as a String.</li>
51  * </ol>
52  *
53  * This class extends Applet which ultimately causes this class to implement Serializable.
54  * This is a serious restriction on this class. All fields that are not transient and not
55  * static are written-out/read-in during serialization. So even private fields essentially
56  * become part of the API. Developers need to take care when modifying fields.
57  * @xsl.usage general
58  */

59 public class XSLTProcessorApplet extends Applet JavaDoc
60 {
61
62   /**
63    * The stylesheet processor.
64    * This field is now transient because a
65    * javax.xml.transform.TransformerFactory from JAXP
66    * makes no claims to be serializable.
67    */

68   transient TransformerFactory JavaDoc m_tfactory = null;
69
70   /**
71    * @serial
72    */

73   private String JavaDoc m_styleURL;
74
75   /**
76    * @serial
77    */

78   private String JavaDoc m_documentURL;
79
80   // Parameter names. To change a name of a parameter, you need only make
81
// a single change. Simply modify the value of the parameter string below.
82
//--------------------------------------------------------------------------
83

84   /**
85    * @serial
86    */

87   private final String JavaDoc PARAM_styleURL = "styleURL";
88
89   /**
90    * @serial
91    */

92   private final String JavaDoc PARAM_documentURL = "documentURL";
93
94
95   // We'll keep the DOM trees around, so tell which trees
96
// are cached.
97

98   /**
99    * @serial
100    */

101   private String JavaDoc m_styleURLOfCached = null;
102
103   /**
104    * @serial
105    */

106   private String JavaDoc m_documentURLOfCached = null;
107
108   /**
109    * Save this for use on the worker thread; may not be necessary.
110    * @serial
111    */

112   private URL JavaDoc m_codeBase = null;
113   
114   /**
115    * @serial
116    */

117   private String JavaDoc m_treeURL = null;
118
119   /**
120    * DocumentBase URL
121    * @serial
122    */

123   private URL JavaDoc m_documentBase = null;
124
125   /**
126    * Thread stuff for the trusted worker thread.
127    */

128   transient private Thread JavaDoc m_callThread = null;
129
130   /**
131    */

132   transient private TrustedAgent m_trustedAgent = null;
133
134   /**
135    * Thread for running TrustedAgent.
136    */

137   transient private Thread JavaDoc m_trustedWorker = null;
138
139   /**
140    * Where the worker thread puts the HTML text.
141    */

142   transient private String JavaDoc m_htmlText = null;
143   
144   /**
145    * Where the worker thread puts the document/stylesheet text.
146    */

147   transient private String JavaDoc m_sourceText = null;
148   
149   /**
150    * Stylesheet attribute name and value that the caller can set.
151    */

152   transient private String JavaDoc m_nameOfIDAttrOfElemToModify = null;
153
154   /**
155    */

156   transient private String JavaDoc m_elemIdToModify = null;
157
158   /**
159    */

160   transient private String JavaDoc m_attrNameToSet = null;
161
162   /**
163    */

164   transient private String JavaDoc m_attrValueToSet = null;
165
166   /**
167    * The XSLTProcessorApplet constructor takes no arguments.
168    */

169   public XSLTProcessorApplet(){}
170
171   /**
172    * Get basic information about the applet
173    * @return A String with the applet name and author.
174    */

175   public String JavaDoc getAppletInfo()
176   {
177     return "Name: XSLTProcessorApplet\r\n" + "Author: Scott Boag";
178   }
179
180   /**
181    * Get descriptions of the applet parameters.
182    * @return A two-dimensional array of Strings with Name, Type, and Description
183    * for each parameter.
184    */

185   public String JavaDoc[][] getParameterInfo()
186   {
187
188     String JavaDoc[][] info =
189     {
190       { PARAM_styleURL, "String", "URL to an XSL stylesheet" },
191       { PARAM_documentURL, "String", "URL to an XML document" },
192     };
193
194     return info;
195   }
196
197   /**
198    * Standard applet initialization.
199    */

200   public void init()
201   {
202
203     // PARAMETER SUPPORT
204
// The following code retrieves the value of each parameter
205
// specified with the <PARAM> tag and stores it in a member
206
// variable.
207
//----------------------------------------------------------------------
208
String JavaDoc param;
209
210     // styleURL: Parameter description
211
//----------------------------------------------------------------------
212
param = getParameter(PARAM_styleURL);
213     
214     // stylesheet parameters
215
m_parameters = new Hashtable JavaDoc();
216
217     if (param != null)
218       setStyleURL(param);
219
220     // documentURL: Parameter description
221
//----------------------------------------------------------------------
222
param = getParameter(PARAM_documentURL);
223
224     if (param != null)
225       setDocumentURL(param);
226
227     m_codeBase = this.getCodeBase();
228     m_documentBase = this.getDocumentBase();
229
230     // If you use a ResourceWizard-generated "control creator" class to
231
// arrange controls in your applet, you may want to call its
232
// CreateControls() method from within this method. Remove the following
233
// call to resize() before adding the call to CreateControls();
234
// CreateControls() does its own resizing.
235
//----------------------------------------------------------------------
236
resize(320, 240);
237   }
238   
239     /**
240    * Automatically called when the HTML client containing the applet loads.
241    * This method starts execution of the applet thread.
242    */

243   public void start()
244   {
245       //check if user code's on the stack before invoking the worker thread
246
boolean passed = false;
247      try {
248        java.security.AccessController.checkPermission(new java.security.AllPermission JavaDoc());
249      } catch (SecurityException JavaDoc se) {
250          //expected
251
passed = true;
252      }
253      if (!passed) {
254          throw new SecurityException JavaDoc("The XSLTProcessorApplet class must be extended and its method start() overridden.");
255      }
256      
257     m_trustedAgent = new TrustedAgent();
258     Thread JavaDoc currentThread = Thread.currentThread();
259     m_trustedWorker = new Thread JavaDoc(currentThread.getThreadGroup(),
260                                  m_trustedAgent);
261     m_trustedWorker.start();
262     try
263     {
264       m_tfactory = TransformerFactory.newInstance();
265       this.showStatus("Causing Transformer and Parser to Load and JIT...");
266
267       // Prime the pump so that subsequent transforms are faster.
268
StringReader JavaDoc xmlbuf = new StringReader JavaDoc("<?xml version='1.0'?><foo/>");
269       StringReader JavaDoc xslbuf = new StringReader JavaDoc(
270         "<?xml version='1.0'?><xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'><xsl:template match='foo'><out/></xsl:template></xsl:stylesheet>");
271       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(new StringWriter JavaDoc());
272
273       synchronized (m_tfactory)
274       {
275         Templates JavaDoc templates = m_tfactory.newTemplates(new StreamSource JavaDoc(xslbuf));
276         Transformer JavaDoc transformer = templates.newTransformer();
277         transformer.transform(new StreamSource JavaDoc(xmlbuf), new StreamResult JavaDoc(pw));
278       }
279       System.out.println("Primed the pump!");
280       this.showStatus("Ready to go!");
281     }
282     catch (Exception JavaDoc e)
283     {
284       this.showStatus("Could not prime the pump!");
285       System.out.println("Could not prime the pump!");
286       e.printStackTrace();
287     }
288   }
289
290   /**
291    * Do not call; this applet contains no UI or visual components.
292    *
293    */

294   public void paint(Graphics JavaDoc g){}
295   
296   /**
297    * Automatically called when the HTML page containing the applet is no longer
298    * on the screen. Stops execution of the applet thread.
299    */

300   public void stop()
301   {
302     if (null != m_trustedWorker)
303     {
304       m_trustedWorker.stop();
305
306       // m_trustedWorker.destroy();
307
m_trustedWorker = null;
308     }
309
310     m_styleURLOfCached = null;
311     m_documentURLOfCached = null;
312   }
313   
314   /**
315    * Cleanup; called when applet is terminated and unloaded.
316    */

317   public void destroy()
318   {
319     if (null != m_trustedWorker)
320     {
321       m_trustedWorker.stop();
322
323       // m_trustedWorker.destroy();
324
m_trustedWorker = null;
325     }
326     m_styleURLOfCached = null;
327     m_documentURLOfCached = null;
328   }
329
330   /**
331    * Set the URL to the XSL stylesheet that will be used
332    * to transform the input XML. No processing is done yet.
333    * @param urlString valid URL string for XSL stylesheet.
334    */

335   public void setStyleURL(String JavaDoc urlString)
336   {
337     m_styleURL = urlString;
338   }
339
340   /**
341    * Set the URL to the XML document that will be transformed
342    * with the XSL stylesheet. No processing is done yet.
343    * @param urlString valid URL string for XML document.
344    */

345   public void setDocumentURL(String JavaDoc urlString)
346   {
347     m_documentURL = urlString;
348   }
349
350   /**
351    * The processor keeps a cache of the source and
352    * style trees, so call this method if they have changed
353    * or you want to do garbage collection.
354    */

355   public void freeCache()
356   {
357     m_styleURLOfCached = null;
358     m_documentURLOfCached = null;
359   }
360
361   /**
362    * Set an attribute in the stylesheet, which gives the ability
363    * to have some dynamic selection control.
364    * @param nameOfIDAttrOfElemToModify The name of an attribute to search for a unique id.
365    * @param elemId The unique ID to look for.
366    * @param attrName Once the element is found, the name of the attribute to set.
367    * @param value The value to set the attribute to.
368    */

369   public void setStyleSheetAttribute(String JavaDoc nameOfIDAttrOfElemToModify,
370                                      String JavaDoc elemId, String JavaDoc attrName,
371                                      String JavaDoc value)
372   {
373     m_nameOfIDAttrOfElemToModify = nameOfIDAttrOfElemToModify;
374     m_elemIdToModify = elemId;
375     m_attrNameToSet = attrName;
376     m_attrValueToSet = value;
377   }
378
379
380   /**
381    * Stylesheet parameter key/value pair stored in a hashtable
382    */

383   transient Hashtable JavaDoc m_parameters;
384
385   /**
386    * Submit a stylesheet parameter.
387    *
388    * @param key stylesheet parameter key
389    * @param expr the parameter expression to be submitted.
390    * @see javax.xml.transform.Transformer#setParameter(String,Object)
391    */

392   public void setStylesheetParam(String JavaDoc key, String JavaDoc expr)
393   {
394     m_parameters.put(key, expr);
395   }
396
397   /**
398    * Given a String containing markup, escape the markup so it
399    * can be displayed in the browser.
400    *
401    * @param s String to escape
402    *
403    * The escaped string.
404    */

405   public String JavaDoc escapeString(String JavaDoc s)
406   {
407     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
408     int length = s.length();
409
410     for (int i = 0; i < length; i++)
411     {
412       char ch = s.charAt(i);
413
414       if ('<' == ch)
415       {
416         sb.append("&lt;");
417       }
418       else if ('>' == ch)
419       {
420         sb.append("&gt;");
421       }
422       else if ('&' == ch)
423       {
424         sb.append("&amp;");
425       }
426       else if (0xd800 <= ch && ch < 0xdc00)
427       {
428         // UTF-16 surrogate
429
int next;
430
431         if (i + 1 >= length)
432         {
433           throw new RuntimeException JavaDoc(
434             XSLMessages.createMessage(
435               XSLTErrorResources.ER_INVALID_UTF16_SURROGATE,
436               new Object JavaDoc[]{ Integer.toHexString(ch) })); //"Invalid UTF-16 surrogate detected: "
437

438           //+Integer.toHexString(ch)+ " ?");
439
}
440         else
441         {
442           next = s.charAt(++i);
443
444           if (!(0xdc00 <= next && next < 0xe000))
445             throw new RuntimeException JavaDoc(
446               XSLMessages.createMessage(
447                 XSLTErrorResources.ER_INVALID_UTF16_SURROGATE,
448                 new Object JavaDoc[]{
449                   Integer.toHexString(ch) + " "
450                   + Integer.toHexString(next) })); //"Invalid UTF-16 surrogate detected: "
451

452           //+Integer.toHexString(ch)+" "+Integer.toHexString(next));
453
next = ((ch - 0xd800) << 10) + next - 0xdc00 + 0x00010000;
454         }
455         sb.append("&#x");
456         sb.append(Integer.toHexString(next));
457         sb.append(";");
458       }
459       else
460       {
461         sb.append(ch);
462       }
463     }
464     return sb.toString();
465   }
466
467   /**
468    * Assuming the stylesheet URL and the input XML URL have been set,
469    * perform the transformation and return the result as a String.
470    *
471    * @return A string that contains the contents pointed to by the URL.
472    *
473    */

474   public String JavaDoc getHtmlText()
475   {
476     m_trustedAgent.m_getData = true;
477     m_callThread = Thread.currentThread();
478     try
479     {
480       synchronized (m_callThread)
481       {
482         m_callThread.wait();
483       }
484     }
485     catch (InterruptedException JavaDoc ie)
486     {
487       System.out.println(ie.getMessage());
488     }
489     return m_htmlText;
490   }
491
492   /**
493    * Get an XML document (or stylesheet)
494    *
495    * @param treeURL valid URL string for the document.
496    *
497    * @return document
498    *
499    * @throws IOException
500    */

501   public String JavaDoc getTreeAsText(String JavaDoc treeURL) throws IOException JavaDoc
502   {
503     m_treeURL = treeURL;
504     m_trustedAgent.m_getData = true;
505     m_trustedAgent.m_getSource = true;
506     m_callThread = Thread.currentThread();
507     try
508     {
509       synchronized (m_callThread)
510       {
511         m_callThread.wait();
512       }
513     }
514     catch (InterruptedException JavaDoc ie)
515     {
516       System.out.println(ie.getMessage());
517     }
518     return m_sourceText;
519   }
520   
521   /**
522    * Use a Transformer to copy the source document
523    * to a StreamResult.
524    *
525    * @return the document as a string
526    */

527   private String JavaDoc getSource() throws TransformerException JavaDoc
528   {
529     StringWriter JavaDoc osw = new StringWriter JavaDoc();
530     PrintWriter JavaDoc pw = new PrintWriter JavaDoc(osw, false);
531     String JavaDoc text = "";
532     try
533     {
534       URL JavaDoc docURL = new URL JavaDoc(m_documentBase, m_treeURL);
535       synchronized (m_tfactory)
536       {
537         Transformer JavaDoc transformer = m_tfactory.newTransformer();
538         StreamSource JavaDoc source = new StreamSource JavaDoc(docURL.toString());
539         StreamResult JavaDoc result = new StreamResult JavaDoc(pw);
540         transformer.transform(source, result);
541         text = osw.toString();
542       }
543     }
544     catch (MalformedURLException JavaDoc e)
545     {
546       e.printStackTrace();
547       throw new RuntimeException JavaDoc(e.getMessage());
548     }
549     catch (Exception JavaDoc any_error)
550     {
551       any_error.printStackTrace();
552     }
553     return text;
554   }
555
556   /**
557    * Get the XML source Tree as a text string suitable
558    * for display in a browser. Note that this is for display of the
559    * XML itself, not for rendering of HTML by the browser.
560    *
561    * @return XML source document as a string.
562    * @throws Exception thrown if tree can not be converted.
563    */

564   public String JavaDoc getSourceTreeAsText() throws Exception JavaDoc
565   {
566     return getTreeAsText(m_documentURL);
567   }
568
569   /**
570    * Get the XSL style Tree as a text string suitable
571    * for display in a browser. Note that this is for display of the
572    * XML itself, not for rendering of HTML by the browser.
573    *
574    * @return The XSL stylesheet as a string.
575    * @throws Exception thrown if tree can not be converted.
576    */

577   public String JavaDoc getStyleTreeAsText() throws Exception JavaDoc
578   {
579     return getTreeAsText(m_styleURL);
580   }
581
582   /**
583    * Get the HTML result Tree as a text string suitable
584    * for display in a browser. Note that this is for display of the
585    * XML itself, not for rendering of HTML by the browser.
586    *
587    * @return Transformation result as unmarked text.
588    * @throws Exception thrown if tree can not be converted.
589    */

590   public String JavaDoc getResultTreeAsText() throws Exception JavaDoc
591   {
592     return escapeString(getHtmlText());
593   }
594
595   /**
596    * Process a document and a stylesheet and return
597    * the transformation result. If one of these is null, the
598    * existing value (of a previous transformation) is not affected.
599    *
600    * @param doc URL string to XML document
601    * @param style URL string to XSL stylesheet
602    *
603    * @return HTML transformation result
604    */

605   public String JavaDoc transformToHtml(String JavaDoc doc, String JavaDoc style)
606   {
607
608     if (null != doc)
609     {
610       m_documentURL = doc;
611     }
612
613     if (null != style)
614     {
615       m_styleURL = style;
616     }
617
618     return getHtmlText();
619   }
620
621   /**
622    * Process a document and a stylesheet and return
623    * the transformation result. Use the xsl:stylesheet PI to find the
624    * document, if one exists.
625    *
626    * @param doc URL string to XML document containing an xsl:stylesheet PI.
627    *
628    * @return HTML transformation result
629    */

630   public String JavaDoc transformToHtml(String JavaDoc doc)
631   {
632
633     if (null != doc)
634     {
635       m_documentURL = doc;
636     }
637
638     m_styleURL = null;
639
640     return getHtmlText();
641   }
642
643
644   /**
645    * Process the transformation.
646    *
647    * @return The transformation result as a string.
648    *
649    * @throws TransformerException
650    */

651   private String JavaDoc processTransformation() throws TransformerException JavaDoc
652   {
653     String JavaDoc htmlData = null;
654     this.showStatus("Waiting for Transformer and Parser to finish loading and JITing...");
655     
656     synchronized (m_tfactory)
657     {
658      URL JavaDoc documentURL = null;
659       URL JavaDoc styleURL = null;
660       StringWriter JavaDoc osw = new StringWriter JavaDoc();
661       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(osw, false);
662       StreamResult JavaDoc result = new StreamResult JavaDoc(pw);
663     
664       this.showStatus("Begin Transformation...");
665       try
666       {
667         documentURL = new URL JavaDoc(m_codeBase, m_documentURL);
668         StreamSource JavaDoc xmlSource = new StreamSource JavaDoc(documentURL.toString());
669
670         styleURL = new URL JavaDoc(m_codeBase, m_styleURL);
671         StreamSource JavaDoc xslSource = new StreamSource JavaDoc(styleURL.toString());
672
673         Transformer JavaDoc transformer = m_tfactory.newTransformer(xslSource);
674
675         
676         Enumeration JavaDoc m_keys = m_parameters.keys();
677         while (m_keys.hasMoreElements()){
678           Object JavaDoc key = m_keys.nextElement();
679           Object JavaDoc expression = m_parameters.get(key);
680           transformer.setParameter((String JavaDoc) key, expression);
681         }
682         transformer.transform(xmlSource, result);
683       }
684       catch (TransformerConfigurationException JavaDoc tfe)
685       {
686         tfe.printStackTrace();
687         throw new RuntimeException JavaDoc(tfe.getMessage());
688       }
689       catch (MalformedURLException JavaDoc e)
690       {
691         e.printStackTrace();
692         throw new RuntimeException JavaDoc(e.getMessage());
693       }
694       
695       this.showStatus("Transformation Done!");
696       htmlData = osw.toString();
697     }
698     return htmlData;
699   }
700
701   /**
702    * This class maintains a worker thread that that is
703    * trusted and can do things like access data. You need
704    * this because the thread that is called by the browser
705    * is not trusted and can't access data from the URLs.
706    */

707   class TrustedAgent implements Runnable JavaDoc
708   {
709
710     /**
711      * Specifies whether the worker thread should perform a transformation.
712      */

713     public boolean m_getData = false;
714
715     /**
716      * Specifies whether the worker thread should get an XML document or XSL stylesheet.
717      */

718     public boolean m_getSource = false;
719
720     /**
721      * The real work is done from here.
722      *
723      */

724     public void run()
725     {
726       while (true)
727       {
728         m_trustedWorker.yield();
729
730         if (m_getData) // Perform a transformation or get a document.
731
{
732           try
733           {
734             m_getData = false;
735             m_htmlText = null;
736             m_sourceText = null;
737             if (m_getSource) // Get a document.
738
{
739               m_getSource = false;
740               m_sourceText = getSource();
741             }
742             else // Perform a transformation.
743
m_htmlText = processTransformation();
744           }
745           catch (Exception JavaDoc e)
746           {
747             e.printStackTrace();
748           }
749           finally
750           {
751             synchronized (m_callThread)
752             {
753               m_callThread.notify();
754             }
755           }
756         }
757         else
758         {
759           try
760           {
761             m_trustedWorker.sleep(50);
762           }
763           catch (InterruptedException JavaDoc ie)
764           {
765             ie.printStackTrace();
766           }
767         }
768       }
769     }
770   }
771   
772   // For compatiblity with old serialized objects
773
// We will change non-serialized fields and change methods
774
// and not have this break us.
775
private static final long serialVersionUID=4618876841979251422L;
776   
777   // For compatibility when de-serializing old objects
778
private void readObject(java.io.ObjectInputStream JavaDoc inStream) throws IOException JavaDoc, ClassNotFoundException JavaDoc
779   {
780       inStream.defaultReadObject();
781       
782       // Needed assignment of non-serialized fields
783

784       // A TransformerFactory is not guaranteed to be serializable,
785
// so we create one here
786
m_tfactory = TransformerFactory.newInstance();
787   }
788 }
789
Popular Tags