KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > 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.21 2004/02/11 05:22:02 minchau Exp $
18  */

19 package org.apache.xalan.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 org.apache.xalan.res.XSLMessages;
41 import org.apache.xalan.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  * @xsl.usage general
53  */

54 public class XSLTProcessorApplet extends Applet JavaDoc
55 {
56
57   /**
58    * The stylesheet processor.
59    * @serial
60    */

61   TransformerFactory JavaDoc m_tfactory = null;
62
63   /**
64    * @serial
65    */

66   private String JavaDoc m_styleURL;
67
68   /**
69    * @serial
70    */

71   private String JavaDoc m_documentURL;
72
73   // Parameter names. To change a name of a parameter, you need only make
74
// a single change. Simply modify the value of the parameter string below.
75
//--------------------------------------------------------------------------
76

77   /**
78    * @serial
79    */

80   private final String JavaDoc PARAM_styleURL = "styleURL";
81
82   /**
83    * @serial
84    */

85   private final String JavaDoc PARAM_documentURL = "documentURL";
86
87
88   // We'll keep the DOM trees around, so tell which trees
89
// are cached.
90

91   /**
92    * @serial
93    */

94   private String JavaDoc m_styleURLOfCached = null;
95
96   /**
97    * @serial
98    */

99   private String JavaDoc m_documentURLOfCached = null;
100
101   /**
102    * Save this for use on the worker thread; may not be necessary.
103    * @serial
104    */

105   private URL JavaDoc m_codeBase = null;
106   
107   /**
108    * @serial
109    */

110   private String JavaDoc m_treeURL = null;
111
112   /**
113    * DocumentBase URL
114    * @serial
115    */

116   private URL JavaDoc m_documentBase = null;
117
118   /**
119    * Thread stuff for the trusted worker thread.
120    */

121   transient private Thread JavaDoc m_callThread = null;
122
123   /**
124    */

125   transient private TrustedAgent m_trustedAgent = null;
126
127   /**
128    * Thread for running TrustedAgent.
129    */

130   transient private Thread JavaDoc m_trustedWorker = null;
131
132   /**
133    * Where the worker thread puts the HTML text.
134    */

135   transient private String JavaDoc m_htmlText = null;
136   
137   /**
138    * Where the worker thread puts the document/stylesheet text.
139    */

140   transient private String JavaDoc m_sourceText = null;
141   
142   /**
143    * Stylesheet attribute name and value that the caller can set.
144    */

145   transient private String JavaDoc m_nameOfIDAttrOfElemToModify = null;
146
147   /**
148    */

149   transient private String JavaDoc m_elemIdToModify = null;
150
151   /**
152    */

153   transient private String JavaDoc m_attrNameToSet = null;
154
155   /**
156    */

157   transient private String JavaDoc m_attrValueToSet = null;
158
159   /**
160    * The XSLTProcessorApplet constructor takes no arguments.
161    */

162   public XSLTProcessorApplet(){}
163
164   /**
165    * Get basic information about the applet
166    * @return A String with the applet name and author.
167    */

168   public String JavaDoc getAppletInfo()
169   {
170     return "Name: XSLTProcessorApplet\r\n" + "Author: Scott Boag";
171   }
172
173   /**
174    * Get descriptions of the applet parameters.
175    * @return A two-dimensional array of Strings with Name, Type, and Description
176    * for each parameter.
177    */

178   public String JavaDoc[][] getParameterInfo()
179   {
180
181     String JavaDoc[][] info =
182     {
183       { PARAM_styleURL, "String", "URL to an XSL stylesheet" },
184       { PARAM_documentURL, "String", "URL to an XML document" },
185     };
186
187     return info;
188   }
189
190   /**
191    * Standard applet initialization.
192    */

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

236   public void start()
237   {
238
239     m_trustedAgent = new TrustedAgent();
240     Thread JavaDoc currentThread = Thread.currentThread();
241     m_trustedWorker = new Thread JavaDoc(currentThread.getThreadGroup(),
242                                  m_trustedAgent);
243     m_trustedWorker.start();
244     try
245     {
246       m_tfactory = TransformerFactory.newInstance();
247       this.showStatus("Causing Transformer and Parser to Load and JIT...");
248
249       // Prime the pump so that subsequent transforms are faster.
250
StringReader JavaDoc xmlbuf = new StringReader JavaDoc("<?xml version='1.0'?><foo/>");
251       StringReader JavaDoc xslbuf = new StringReader JavaDoc(
252         "<?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>");
253       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(new StringWriter JavaDoc());
254
255       synchronized (m_tfactory)
256       {
257         Templates JavaDoc templates = m_tfactory.newTemplates(new StreamSource JavaDoc(xslbuf));
258         Transformer JavaDoc transformer = templates.newTransformer();
259         transformer.transform(new StreamSource JavaDoc(xmlbuf), new StreamResult JavaDoc(pw));
260       }
261       System.out.println("Primed the pump!");
262       this.showStatus("Ready to go!");
263     }
264     catch (Exception JavaDoc e)
265     {
266       this.showStatus("Could not prime the pump!");
267       System.out.println("Could not prime the pump!");
268       e.printStackTrace();
269     }
270   }
271
272   /**
273    * Do not call; this applet contains no UI or visual components.
274    *
275    */

276   public void paint(Graphics JavaDoc g){}
277   
278   /**
279    * Automatically called when the HTML page containing the applet is no longer
280    * on the screen. Stops execution of the applet thread.
281    */

282   public void stop()
283   {
284     if (null != m_trustedWorker)
285     {
286       m_trustedWorker.stop();
287
288       // m_trustedWorker.destroy();
289
m_trustedWorker = null;
290     }
291
292     m_styleURLOfCached = null;
293     m_documentURLOfCached = null;
294   }
295   
296   /**
297    * Cleanup; called when applet is terminated and unloaded.
298    */

299   public void destroy()
300   {
301     if (null != m_trustedWorker)
302     {
303       m_trustedWorker.stop();
304
305       // m_trustedWorker.destroy();
306
m_trustedWorker = null;
307     }
308     m_styleURLOfCached = null;
309     m_documentURLOfCached = null;
310   }
311
312   /**
313    * Set the URL to the XSL stylesheet that will be used
314    * to transform the input XML. No processing is done yet.
315    * @param urlString valid URL string for XSL stylesheet.
316    */

317   public void setStyleURL(String JavaDoc urlString)
318   {
319     m_styleURL = urlString;
320   }
321
322   /**
323    * Set the URL to the XML document that will be transformed
324    * with the XSL stylesheet. No processing is done yet.
325    * @param urlString valid URL string for XML document.
326    */

327   public void setDocumentURL(String JavaDoc urlString)
328   {
329     m_documentURL = urlString;
330   }
331
332   /**
333    * The processor keeps a cache of the source and
334    * style trees, so call this method if they have changed
335    * or you want to do garbage collection.
336    */

337   public void freeCache()
338   {
339     m_styleURLOfCached = null;
340     m_documentURLOfCached = null;
341   }
342
343   /**
344    * Set an attribute in the stylesheet, which gives the ability
345    * to have some dynamic selection control.
346    * @param nameOfIDAttrOfElemToModify The name of an attribute to search for a unique id.
347    * @param elemId The unique ID to look for.
348    * @param attrName Once the element is found, the name of the attribute to set.
349    * @param value The value to set the attribute to.
350    */

351   public void setStyleSheetAttribute(String JavaDoc nameOfIDAttrOfElemToModify,
352                                      String JavaDoc elemId, String JavaDoc attrName,
353                                      String JavaDoc value)
354   {
355     m_nameOfIDAttrOfElemToModify = nameOfIDAttrOfElemToModify;
356     m_elemIdToModify = elemId;
357     m_attrNameToSet = attrName;
358     m_attrValueToSet = value;
359   }
360
361   /**
362    * Stylesheet parameter keys
363    */

364   private Enumeration JavaDoc m_keys;
365
366   /**
367    * Stylesheet parameter key/value pair stored in a hashtable
368    */

369   transient Hashtable JavaDoc m_parameters;
370
371   /**
372    * Submit a stylesheet parameter.
373    *
374    * @param key stylesheet parameter key
375    * @param expr the parameter expression to be submitted.
376    * @see javax.xml.transform.Transformer#setParameter(String,Object)
377    */

378   public void setStylesheetParam(String JavaDoc key, String JavaDoc expr)
379   {
380     m_parameters.put(key, expr);
381   }
382
383   /**
384    * Given a String containing markup, escape the markup so it
385    * can be displayed in the browser.
386    *
387    * @param s String to escape
388    *
389    * The escaped string.
390    */

391   public String JavaDoc escapeString(String JavaDoc s)
392   {
393     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
394     int length = s.length();
395
396     for (int i = 0; i < length; i++)
397     {
398       char ch = s.charAt(i);
399
400       if ('<' == ch)
401       {
402         sb.append("&lt;");
403       }
404       else if ('>' == ch)
405       {
406         sb.append("&gt;");
407       }
408       else if ('&' == ch)
409       {
410         sb.append("&amp;");
411       }
412       else if (0xd800 <= ch && ch < 0xdc00)
413       {
414         // UTF-16 surrogate
415
int next;
416
417         if (i + 1 >= length)
418         {
419           throw new RuntimeException JavaDoc(
420             XSLMessages.createMessage(
421               XSLTErrorResources.ER_INVALID_UTF16_SURROGATE,
422               new Object JavaDoc[]{ Integer.toHexString(ch) })); //"Invalid UTF-16 surrogate detected: "
423

424           //+Integer.toHexString(ch)+ " ?");
425
}
426         else
427         {
428           next = s.charAt(++i);
429
430           if (!(0xdc00 <= next && next < 0xe000))
431             throw new RuntimeException JavaDoc(
432               XSLMessages.createMessage(
433                 XSLTErrorResources.ER_INVALID_UTF16_SURROGATE,
434                 new Object JavaDoc[]{
435                   Integer.toHexString(ch) + " "
436                   + Integer.toHexString(next) })); //"Invalid UTF-16 surrogate detected: "
437

438           //+Integer.toHexString(ch)+" "+Integer.toHexString(next));
439
next = ((ch - 0xd800) << 10) + next - 0xdc00 + 0x00010000;
440         }
441         sb.append("&#x");
442         sb.append(Integer.toHexString(next));
443         sb.append(";");
444       }
445       else
446       {
447         sb.append(ch);
448       }
449     }
450     return sb.toString();
451   }
452
453   /**
454    * Assuming the stylesheet URL and the input XML URL have been set,
455    * perform the transformation and return the result as a String.
456    *
457    * @return A string that contains the contents pointed to by the URL.
458    *
459    */

460   public String JavaDoc getHtmlText()
461   {
462     m_trustedAgent.m_getData = true;
463     m_callThread = Thread.currentThread();
464     try
465     {
466       synchronized (m_callThread)
467       {
468         m_callThread.wait();
469       }
470     }
471     catch (InterruptedException JavaDoc ie)
472     {
473       System.out.println(ie.getMessage());
474     }
475     return m_htmlText;
476   }
477
478   /**
479    * Get an XML document (or stylesheet)
480    *
481    * @param treeURL valid URL string for the document.
482    *
483    * @return document
484    *
485    * @throws IOException
486    */

487   public String JavaDoc getTreeAsText(String JavaDoc treeURL) throws IOException JavaDoc
488   {
489     m_treeURL = treeURL;
490     m_trustedAgent.m_getData = true;
491     m_trustedAgent.m_getSource = true;
492     m_callThread = Thread.currentThread();
493     try
494     {
495       synchronized (m_callThread)
496       {
497         m_callThread.wait();
498       }
499     }
500     catch (InterruptedException JavaDoc ie)
501     {
502       System.out.println(ie.getMessage());
503     }
504     return m_sourceText;
505   }
506   
507   /**
508    * Use a Transformer to copy the source document
509    * to a StreamResult.
510    *
511    * @return the document as a string
512    */

513   private String JavaDoc getSource() throws TransformerException JavaDoc
514   {
515     StringWriter JavaDoc osw = new StringWriter JavaDoc();
516     PrintWriter JavaDoc pw = new PrintWriter JavaDoc(osw, false);
517     String JavaDoc text = "";
518     try
519     {
520       URL JavaDoc docURL = new URL JavaDoc(m_documentBase, m_treeURL);
521       synchronized (m_tfactory)
522       {
523         Transformer JavaDoc transformer = m_tfactory.newTransformer();
524         StreamSource JavaDoc source = new StreamSource JavaDoc(docURL.toString());
525         StreamResult JavaDoc result = new StreamResult JavaDoc(pw);
526         transformer.transform(source, result);
527         text = osw.toString();
528       }
529     }
530     catch (MalformedURLException JavaDoc e)
531     {
532       e.printStackTrace();
533       System.exit(-1);
534     }
535     catch (Exception JavaDoc any_error)
536     {
537       any_error.printStackTrace();
538     }
539     return text;
540   }
541
542   /**
543    * Get the XML source Tree as a text string suitable
544    * for display in a browser. Note that this is for display of the
545    * XML itself, not for rendering of HTML by the browser.
546    *
547    * @return XML source document as a string.
548    * @throws Exception thrown if tree can not be converted.
549    */

550   public String JavaDoc getSourceTreeAsText() throws Exception JavaDoc
551   {
552     return getTreeAsText(m_documentURL);
553   }
554
555   /**
556    * Get the XSL style Tree as a text string suitable
557    * for display in a browser. Note that this is for display of the
558    * XML itself, not for rendering of HTML by the browser.
559    *
560    * @return The XSL stylesheet as a string.
561    * @throws Exception thrown if tree can not be converted.
562    */

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

576   public String JavaDoc getResultTreeAsText() throws Exception JavaDoc
577   {
578     return escapeString(getHtmlText());
579   }
580
581   /**
582    * Process a document and a stylesheet and return
583    * the transformation result. If one of these is null, the
584    * existing value (of a previous transformation) is not affected.
585    *
586    * @param doc URL string to XML document
587    * @param style URL string to XSL stylesheet
588    *
589    * @return HTML transformation result
590    */

591   public String JavaDoc transformToHtml(String JavaDoc doc, String JavaDoc style)
592   {
593
594     if (null != doc)
595     {
596       m_documentURL = doc;
597     }
598
599     if (null != style)
600     {
601       m_styleURL = style;
602     }
603
604     return getHtmlText();
605   }
606
607   /**
608    * Process a document and a stylesheet and return
609    * the transformation result. Use the xsl:stylesheet PI to find the
610    * document, if one exists.
611    *
612    * @param doc URL string to XML document containing an xsl:stylesheet PI.
613    *
614    * @return HTML transformation result
615    */

616   public String JavaDoc transformToHtml(String JavaDoc doc)
617   {
618
619     if (null != doc)
620     {
621       m_documentURL = doc;
622     }
623
624     m_styleURL = null;
625
626     return getHtmlText();
627   }
628
629
630   /**
631    * Process the transformation.
632    *
633    * @return The transformation result as a string.
634    *
635    * @throws TransformerException
636    */

637   private String JavaDoc processTransformation() throws TransformerException JavaDoc
638   {
639     String JavaDoc htmlData = null;
640     this.showStatus("Waiting for Transformer and Parser to finish loading and JITing...");
641     
642     synchronized (m_tfactory)
643     {
644      URL JavaDoc documentURL = null;
645       URL JavaDoc styleURL = null;
646       StringWriter JavaDoc osw = new StringWriter JavaDoc();
647       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(osw, false);
648       StreamResult JavaDoc result = new StreamResult JavaDoc(pw);
649     
650       this.showStatus("Begin Transformation...");
651       try
652       {
653         documentURL = new URL JavaDoc(m_codeBase, m_documentURL);
654         StreamSource JavaDoc xmlSource = new StreamSource JavaDoc(documentURL.toString());
655
656         styleURL = new URL JavaDoc(m_codeBase, m_styleURL);
657         StreamSource JavaDoc xslSource = new StreamSource JavaDoc(styleURL.toString());
658
659         Transformer JavaDoc transformer = m_tfactory.newTransformer(xslSource);
660
661         m_keys = m_parameters.keys();
662         while (m_keys.hasMoreElements()){
663           Object JavaDoc key = m_keys.nextElement();
664           Object JavaDoc expression = m_parameters.get(key);
665           transformer.setParameter((String JavaDoc) key, expression);
666         }
667         transformer.transform(xmlSource, result);
668       }
669       catch (TransformerConfigurationException JavaDoc tfe)
670       {
671         tfe.printStackTrace();
672         System.exit(-1);
673       }
674       catch (MalformedURLException JavaDoc e)
675       {
676         e.printStackTrace();
677         System.exit(-1);
678       }
679       
680       this.showStatus("Transformation Done!");
681       htmlData = osw.toString();
682     }
683     return htmlData;
684   }
685
686   /**
687    * This class maintains a worker thread that that is
688    * trusted and can do things like access data. You need
689    * this because the thread that is called by the browser
690    * is not trusted and can't access data from the URLs.
691    */

692   class TrustedAgent implements Runnable JavaDoc
693   {
694
695     /**
696      * Specifies whether the worker thread should perform a transformation.
697      */

698     public boolean m_getData = false;
699
700     /**
701      * Specifies whether the worker thread should get an XML document or XSL stylesheet.
702      */

703     public boolean m_getSource = false;
704
705     /**
706      * The real work is done from here.
707      *
708      */

709     public void run()
710     {
711       while (true)
712       {
713         m_trustedWorker.yield();
714
715         if (m_getData) // Perform a transformation or get a document.
716
{
717           try
718           {
719             m_getData = false;
720             m_htmlText = null;
721             m_sourceText = null;
722             if (m_getSource) // Get a document.
723
{
724               m_getSource = false;
725               m_sourceText = getSource();
726             }
727             else // Perform a transformation.
728
m_htmlText = processTransformation();
729           }
730           catch (Exception JavaDoc e)
731           {
732             e.printStackTrace();
733           }
734           finally
735           {
736             synchronized (m_callThread)
737             {
738               m_callThread.notify();
739             }
740           }
741         }
742         else
743         {
744           try
745           {
746             m_trustedWorker.sleep(50);
747           }
748           catch (InterruptedException JavaDoc ie)
749           {
750             ie.printStackTrace();
751           }
752         }
753       }
754     }
755   }
756 }
757
Popular Tags