KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > servlet > ApplyXSLT


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: ApplyXSLT.java,v 1.22 2004/02/17 19:13:22 minchau Exp $
18  */

19 package servlet;
20
21 import java.io.*;
22 import java.util.*;
23 import javax.servlet.*;
24 import javax.servlet.http.*;
25 import java.net.URL JavaDoc;
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URLConnection JavaDoc;
28 import javax.xml.transform.OutputKeys JavaDoc;
29
30 import org.apache.xalan.templates.Constants;
31 import org.apache.xalan.templates.StylesheetRoot;
32 // SAX2 Imports
33
import org.xml.sax.ContentHandler JavaDoc;
34 import org.xml.sax.SAXException JavaDoc;
35 import org.xml.sax.XMLReader JavaDoc;
36 import org.xml.sax.Locator JavaDoc;
37 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
38 import org.xml.sax.ext.DeclHandler JavaDoc;
39 import org.xml.sax.ext.LexicalHandler JavaDoc;
40 import org.xml.sax.SAXNotRecognizedException JavaDoc;
41 import org.xml.sax.SAXNotSupportedException JavaDoc;
42
43 import org.w3c.dom.*;
44 import javax.xml.transform.*;
45 import javax.xml.transform.stream.*;
46 import org.apache.xalan.transformer.TransformerImpl;
47 import org.apache.xpath.objects.XObject;
48 import org.apache.xpath.objects.XString;
49 import org.apache.xalan.processor.*;
50
51 import javax.xml.parsers.DocumentBuilder JavaDoc;
52 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
53
54 import org.xml.sax.XMLReader JavaDoc;
55 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
56 import org.xml.sax.helpers.XMLFilterImpl JavaDoc;
57
58 /*****************************************************************************************************
59  *
60  * ApplyXSLT supplies the basic
61  * functions for transforming XML data using XSL stylesheets.
62  *
63  * @author Spencer Shepard (sshepard@us.ibm.com)
64  * @author R. Adam King (rak@us.ibm.com)
65  * @author Tom Rowe (trowe@us.ibm.com)
66  * @author Don Leslie (donald_leslie@lotus.com)
67  *
68  *****************************************************************************************************/

69
70 public class ApplyXSLT extends HttpServlet
71 {
72
73   /**
74    * Operational parameters for this class.
75    * <p>Request-time values override init-time values which override class defaults.</p>
76    * @see #init
77    * @serial
78    */

79   protected ApplyXSLTProperties ourDefaultParameters = null;
80
81   /**
82    * String representing the end of line characters for the System.
83    */

84   public final static String JavaDoc EOL = System.getProperty("line.separator");
85
86   /**
87    * String representing the file separator characters for the System.
88    */

89   public final static String JavaDoc FS = System.getProperty("file.separator");
90
91    /**
92    * String representing the current directory for properties files. See init().
93    */

94   public final static String JavaDoc ROOT = System.getProperty("server.root");
95   public static String JavaDoc CURRENTDIR;
96
97   /**
98    * Initialize operational parameters from the configuration.
99    * @param config Configuration
100    * @exception ServletException Never thrown
101    */

102   public void init(ServletConfig config)
103     throws ServletException
104   {
105     super.init(config);
106     // If the server.root property --see above-- is null, use current working directory
107
// as default location for media.properties.
108
if (ROOT != null){
109       CURRENTDIR= getServletContext().getRealPath("/WEB-INF/classes/servlet/") + FS;
110       System.out.println ( CURRENTDIR);}
111     else
112       CURRENTDIR = System.getProperty("user.dir")+ FS;
113     
114     setDefaultParameters(config);
115     
116     setMediaProps(config.getInitParameter("mediaURL"));
117   }
118   
119  /**
120    * Sets the default parameters for the servlet from the configuration.
121    * Also sets required system properties until we figure out why servlet
122    * sometimess fails to read properties from properties files.
123    * @param config Configuration
124    */

125   protected void setDefaultParameters(ServletConfig config)
126   {
127     ourDefaultParameters = new DefaultApplyXSLTProperties(config);
128   }
129   
130   /**
131    * Loads the media properties file specified by the given string.
132    * @param mediaURLstring Location of the media properties file. Can be either a full URL or a path relative
133    * to the System's server.root /servlets directory. If this parameter is null,
134    * server.root/servlets/media.properties will be used.
135    * @see ApplyXSL#CURRENTDIR
136    */

137   protected void setMediaProps(String JavaDoc mediaURLstring)
138   {
139     if (mediaURLstring != null)
140     {
141       URL JavaDoc url = null;
142       try
143       {
144         url = new URL JavaDoc(mediaURLstring);
145       }
146       catch (MalformedURLException JavaDoc mue1)
147       {
148         try
149         {
150           url = new URL JavaDoc("file", "", CURRENTDIR + mediaURLstring);
151         }
152         catch (MalformedURLException JavaDoc mue2)
153         {
154           writeLog("Unable to find the media properties file based on parameter 'mediaURL' = "
155                    + mediaURLstring, HttpServletResponse.SC_ACCEPTED, mue2);
156           url = null;
157         }
158       }
159       if (url != null)
160       {
161         try
162         {
163           ourMediaProps = new OrderedProps(url.openStream());
164         }
165         catch (IOException ioe1)
166         {
167           writeLog("Exception occurred while opening media properties file: " + mediaURLstring +
168                    ". Media table may be invalid.", HttpServletResponse.SC_ACCEPTED, ioe1);
169         }
170       }
171     }
172     else
173     {
174       String JavaDoc defaultProp = CURRENTDIR + "media.properties";
175       try
176       {
177         ourMediaProps = new OrderedProps(new FileInputStream(defaultProp));
178       }
179       catch (IOException ioe2)
180       {
181         writeLog("Default media properties file " + defaultProp + " not found.",
182                  HttpServletResponse.SC_ACCEPTED, ioe2);
183       }
184     }
185   }
186
187   public String JavaDoc getMedia(HttpServletRequest request)
188   {
189     return ourMediaProps.getValue(request.getHeader(HEADER_NAME));
190   }
191   
192   // doPost removed for security reasons due to the possibility of sending
193
// unsecure XML and XSL XSLTInputSources through the request input stream
194

195   /**
196    * HTTP Get method passed on to process().
197    * @param request The request
198    * @param response The response
199    * @see #process
200    * @exception ServletException Never thrown
201    * @exception IOException Never thrown
202    */

203   public void doGet (HttpServletRequest request,
204                      HttpServletResponse response)
205     throws ServletException, IOException
206   {
207     try
208     {
209       TransformerFactory tFactory = TransformerFactory.newInstance();
210       process(tFactory, request, response);
211     }
212     catch (Exception JavaDoc e)
213     {
214     }
215   }
216   
217   /**
218    * Coordinates applying an XSL stylesheet to XML data using operational parameters.
219    * <p>If successfully applied, the result tree will be streamed to the response object
220    * and the content type set according to the XSL stylesheet's &lt;xsl:output> element(s).</p>
221    * <p>If there is a problem in parsing the XML/XSL or if there is a problem in applying
222    * the XSL to the XML, an exception will be streamed to the response object. The detail
223    * of the information returned in the response object will depend on whether we're
224    * running in debug mode or not.</p>
225    * @param processor implementation of TRaX processor
226    * @param request May contain information relevant to creating XML and XSL XSLTInputSource's
227    * @param response Where to write the transformation result
228    * @see #getDocument
229    * @see #getStylesheet
230    * @see #getContentType
231    * @see #displayException
232    * @see #setStylesheetParams
233    * @exception ServletException Never thrown
234    * @exception IOException Never thrown
235    */

236   
237   public void process(TransformerFactory tFactory,
238                       HttpServletRequest request,
239                       HttpServletResponse response)
240     throws ServletException, IOException, SAXException JavaDoc
241   {
242     boolean debug = ourDefaultParameters.isDebug(request);
243
244     long time = 0;
245     if (debug)
246       time = System.currentTimeMillis();
247
248     // Listener to be used for all reporting
249
ApplyXSLTListener listener = new ApplyXSLTListener();
250     listener.out.println("debug is " + debug);
251
252     StreamSource xmlSource = null;
253     StreamSource xslSource = null;
254     try
255     {
256       if ((xmlSource = getDocument(request, listener)) == null)
257         throw new ApplyXSLTException("getDocument() returned null",
258                                      new NullPointerException JavaDoc(),
259                                      response.SC_NOT_FOUND);
260     }
261     catch (ApplyXSLTException axe)
262     {
263       axe.appendMessage(EOL + "getDocument() resulted in ApplyXSLTException" + EOL
264                         + listener.getMessage());
265       if (debug) writeLog(axe);
266       displayException(response, axe, debug);
267       xmlSource = null;
268     }
269     // creating XSL Stylesheet
270
if (xmlSource != null)
271     {
272       try
273       {
274         if ((xslSource = getStylesheet(tFactory, request, xmlSource, listener)) == null)
275         {
276           throw new ApplyXSLTException("getStylesheet() returned null",
277                                        new NullPointerException JavaDoc(),
278                                        response.SC_NOT_FOUND);
279         }
280         // For time being, must "reset" xmlSource after extracting stylesheet PI
281
xmlSource = getDocument(request, listener);
282       }
283       catch (ApplyXSLTException axe)
284       {
285         axe.appendMessage(EOL + "getStylesheet() resulted in ApplyXSLTException" + EOL
286                           + listener.getMessage());
287         if (debug) writeLog(axe);
288         displayException(response, axe, debug);
289         xslSource = null;
290       }
291     // perform Transformation
292

293     if ((xmlSource != null) && (xslSource != null))
294     {
295       try
296       {
297         listener.out.println("Performing transformation...");
298         
299         Templates templates = tFactory.newTemplates(xslSource);
300         Transformer transformer = templates.newTransformer();
301         {
302           try
303           {
304             String JavaDoc contentType = null;
305                   contentType = getContentType(templates);
306             if (contentType != null);
307               response.setContentType(contentType);
308
309                   if (transformer instanceof TransformerImpl)
310                   {
311                     TransformerImpl transformerImpl = (TransformerImpl)transformer;
312               transformerImpl.setQuietConflictWarnings(ourDefaultParameters.isNoCW(request));
313                   }
314             
315                   setStylesheetParams(transformer, request);
316               transformer.transform(xmlSource, new StreamResult(response.getOutputStream()));
317             
318                   if (debug)
319               writeLog(listener.getMessage(), response.SC_OK);
320           }
321           catch (Exception JavaDoc exc)
322           {
323             ApplyXSLTException axe = new ApplyXSLTException
324                                      ("Exception occurred during Transformation:"
325                                           + EOL + listener.getMessage() + EOL
326                                           + exc.getMessage(),
327                                                   exc,
328                                 response.SC_INTERNAL_SERVER_ERROR);
329             if (debug) writeLog(axe);
330             displayException(response, axe, debug);
331           }
332           finally
333           {
334             // transformer.reset();
335
} // end of try ... catch ... finally
336
}
337       }
338       catch (/*org.xml.sax.SAX*/Exception JavaDoc saxExc)
339       {
340         ApplyXSLTException axe = new ApplyXSLTException
341                                  ("Exception occurred during ctor/Transformation:"
342                                              + EOL + listener.getMessage() + EOL
343                                              + saxExc.getMessage(),
344                                                   saxExc,
345                                   response.SC_INTERNAL_SERVER_ERROR);
346         if (debug) writeLog(axe);
347         displayException(response, axe, debug);
348       } // end of new try ... catch
349
} // end of if((stylesheetRoot != null) ...
350
if (debug)
351     {
352       time = System.currentTimeMillis() - time;
353       writeLog(" No Conflict Warnings = " + ourDefaultParameters.isNoCW(request) +
354                " Transformation time: " + time + " ms", response.SC_OK);
355     }
356   }
357   }
358
359   /**
360    * Returns an XML XSLTInputSource DOM. Attempts will be make to create the DOM from the following
361    * sources:
362    * <ol>
363    * <li>A relative URL specified in the HTTP request's path information. This capability is intended
364    * for use by <b>servlet engines that map</b> some or all XML data to be processed at the server.</li>
365    * <li>A URL specified in the HTTP request's <code>URL=</code> parameter. This capability
366    * is intended for <b>clients wishing to selectively process</b> XML data at the server. For
367    * security reasons, this URL will be forced to the local IP host.</li>
368    * <li>The HTTP request's XML input stream. This capability is intended for use by chained servlets.</li>
369    * </ol>
370    * @param request May contain or point to the XML XSLTInputSource
371    * @param listener To record detailed parsing messages for possible return to requestor
372    * @return XML XSLTInputSource DOM, or null if the XSLTInputSource could not be parsed
373    * @exception ApplyXSLTException Thrown if exception occurs while handling request
374    */

375   protected StreamSource getDocument(HttpServletRequest request,
376                                      ApplyXSLTListener listener)
377     throws ApplyXSLTException
378   {
379     try
380     {
381       String JavaDoc xmlURL = null;
382       // document from PathInfo
383
if ((xmlURL = request.getPathInfo()) != null)
384       {
385         listener.out.println("Parsing XML Document from PathInfo: " + xmlURL);
386         return new StreamSource(new URL JavaDoc("http", ((DefaultApplyXSLTProperties)
387                                          ourDefaultParameters).getLocalHost(),
388                                          request.getServerPort(),
389                                          xmlURL.replace('\\', '/')).openStream());
390       }
391       // document from Request parameter
392
if ((xmlURL = ourDefaultParameters.getXMLurl(request)) != null)
393       {
394         listener.out.println("Parsing XML Document from request parameter: " + xmlURL);
395         return new StreamSource(new URL JavaDoc(xmlURL).openStream());
396       }
397       // document from chain
398
String JavaDoc contentType = request.getContentType();
399       if ((contentType != null) && contentType.startsWith("text/xml"))
400       {
401         listener.out.println("Parsing XML Document from request chain");
402         return new StreamSource(request.getInputStream());
403       }
404     }
405     catch (IOException ioe)
406     {
407       throw new ApplyXSLTException(ioe, HttpServletResponse.SC_NOT_FOUND);
408     }
409     catch (Exception JavaDoc e)
410     {
411       throw new ApplyXSLTException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
412     }
413     return null;
414   }
415
416   /**
417    * Returns a Templates (StylesheetRoot) object. Attempts will be make to create the Stylesheet
418    * from the followingsources:
419    * <ol>
420    * <li>A URL specified in the HTTP request's <code>xslURL=</code> parameter. This capability
421    * is intended for clients wishing to selectively override the server algorithm for applying XSL
422    * stylesheets. For security reasons, this URL will be forced to the local IP host.</li>
423    * <li>XML association. XML documents may contain references to one or more stylesheets using
424    * <a HREF="http://www.w3.org/TR/1999/PR-xml-stylesheet-19990114">this</a> W3C proposed recommendation.
425    * If the XML document does contain such references, a best match will be chosen based on the browser
426    * type making the request and the default association. This capability enables relationships to be
427    * defined between client capabilities and stylesheets capable of acting on these capabilities.</li>
428    * <li>A configured default stylesheet URL</li>
429    * </ol>
430    * @param request May contain or point to the XSL XSLTInputSource
431    * @param xmlSource May point to the XSL XSLTInputSource
432    * @param listener To record detailed parsing messages for possible return to requestor
433    * @return XSL XSLTInputSource, or null if the request could not be parsed
434    * @see #makeDocument
435    * @see #getMedia
436    * @see #STYLESHEET_ATTRIBUTE
437    * @see #getXSLURLfromDoc
438    * @see #toAcceptLanguageConnection
439    * @exception ApplyXSLTException Thrown if exception occurs while handling request
440    */

441   protected StreamSource getStylesheet(TransformerFactory tFactory,
442                                        HttpServletRequest request,
443                                        StreamSource xmlSource,
444                                        ApplyXSLTListener listener)
445     throws ApplyXSLTException
446   {
447     try
448     {
449       //stylesheet URL from request
450
String JavaDoc xslURL = ((DefaultApplyXSLTProperties) ourDefaultParameters).getXSLRequestURL(request);
451
452       if (xslURL != null)
453         listener.out.println("Parsing XSL Stylesheet Document from request parameter: "
454                              + xslURL);
455       else
456       {
457         // find stylesheet from XML Document, Media tag preference
458
if (xmlSource != null){
459           listener.out.println("calling getXSLURLfromDoc and getMedia " + getMedia(request) );
460           xslURL = getXSLURLfromDoc(xmlSource, STYLESHEET_ATTRIBUTE, getMedia(request), tFactory);
461         }
462         if (xslURL != null)
463           listener.out.println("Parsing XSL Stylesheet Document from XML Document tag: " + xslURL);
464         else
465           // Configuration Default
466
if ((xslURL = ourDefaultParameters.getXSLurl(null)) != null)
467             listener.out.println("Parsing XSL Stylesheet Document from configuration: " + xslURL);
468       }
469       return new StreamSource(xslURL);
470     }
471     catch (IOException ioe)
472     {
473       throw new ApplyXSLTException(ioe, HttpServletResponse.SC_NOT_FOUND);
474     }
475     catch (Exception JavaDoc e)
476     {
477       throw new ApplyXSLTException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
478     }
479   }
480
481   /**
482    * Returns the response content type specified by the media-type and encoding attributes of
483    * the &lt;xsl:output> element(s) of the stylesheet.
484    * @param xslSourceRoot XSL Stylesheet to be examined for &lt;xsl:output> elements.
485    * @return The response content type (MIME type and charset) of the stylesheet output
486    * @see #process
487    */

488   public String JavaDoc getContentType(Templates templates)
489   {
490     Properties oprops = templates.getOutputProperties();
491     String JavaDoc encoding = oprops.getProperty(OutputKeys.ENCODING);
492           String JavaDoc media = oprops.getProperty(OutputKeys.MEDIA_TYPE);
493           if (media != null)
494           {
495       if (encoding != null)
496         return media + "; charset=" + encoding;
497       return media;
498           }
499           else
500           {
501             String JavaDoc method = oprops.getProperty(OutputKeys.METHOD);
502             if (method.equals("html"))
503                     return "text/html";
504             else if (method.equals("text"))
505                     return "text/plain";
506             else
507                     return "text/xml";
508           }
509   }
510   
511
512   /**
513    * Defines and sets select top-level XSL stylesheet variables from the HTTP request, which
514    * can be evaluated using &lt;xsl:param-variable&gt;. The following variables will be
515    * automatically set:
516    * <dl>
517    * <dt><i>ParameterName</i></dt>
518    * <dd>Each non-reserved request parameter returned from request.getParameterNames(). If a
519    * parameter contains more than a single value, only the first value is available.</dd>
520    * <dt>servlet-RemoteAddr</dt>
521    * <dd>Contains String output from request.getRemoteAddr(), which is the IP address
522    * of the client machine.</dd>
523    * <dt>servlet-RemoteHost</dt>
524    * <dd>Contains String output from request.getRemoteHost(), which is the host name
525    * of the client machine.</dd>
526    * <dt>servlet-RemoteUser</dt>
527    * <dd>Contains String output from request.getRemoteUser(), which was the user name
528    * accepted by the server to grant access to this servlet.</dd>
529    * <dt>servlet-Request</dt>
530    * <dd>Contains the request object.</dd>
531    * </dl>
532    * @param xslprocessor Where to register parameters to be set
533    * @param request Provides access to all meaningful parameters to set
534    * @see #process
535    */

536   public void setStylesheetParams(Transformer transformer, HttpServletRequest request)
537   {
538     Enumeration paramNames = request.getParameterNames();
539     while (paramNames.hasMoreElements())
540     {
541       String JavaDoc paramName = (String JavaDoc) paramNames.nextElement();
542       try
543       {
544         String JavaDoc[] paramVals = request.getParameterValues(paramName);
545         if (paramVals != null)
546             transformer.setParameter(paramName, new XString(paramVals[0]));
547                                             
548       }
549       catch (Exception JavaDoc e)
550       {
551       }
552     }
553     try
554     {
555       transformer.setParameter("servlet-RemoteAddr", new XString(request.getRemoteAddr()));
556                                       
557     }
558     catch (Exception JavaDoc e)
559     {
560     }
561     try
562     {
563       transformer.setParameter("servlet-RemoteHost", new XString(request.getRemoteHost()));
564                                       
565     }
566     catch (Exception JavaDoc e)
567     {
568     }
569     try
570     {
571       transformer.setParameter("servlet-RemoteUser", new XString(request.getRemoteUser()));
572                                       
573     }
574     catch (Exception JavaDoc e)
575     {
576     }
577   }
578
579
580   /**
581    * Writes the following information to the servlet log:
582    * <ol>
583    * <li>HTTP status code</li>
584    * <li>Message</li>
585    * <li>Stack trace</li>
586    * </ol>
587    * @param axe Contains valid HTTP status code, message, and stack trace (optional)
588    */

589   protected void writeLog(ApplyXSLTException axe)
590   {
591     writeLog(axe.getMessage(), axe.getStatusCode(), axe.getException());
592   }
593
594   /**
595    * Writes the following information to the servlet log:
596    * <ol>
597    * <li>HTTP status code</li>
598    * <li>Message</li>
599    * <li>Stack trace</li>
600    * </ol>
601    * @param msg Message to be logged
602    * @param statusCode Valid status code from javax.servlet.http.HttpServletResponse
603    * @param t Used to generate stack trace (may be =null to suppress stack trace)
604    */

605   protected void writeLog(String JavaDoc msg, int statusCode, Throwable JavaDoc t)
606   {
607     if (t == null)
608       writeLog(msg, statusCode);
609     else
610     {
611       ByteArrayOutputStream bytes = new ByteArrayOutputStream();
612       PrintWriter writer = new PrintWriter(bytes, true);
613       System.out.println("Exception is " + t.getClass().getName());
614       t.printStackTrace(writer);
615       log("HTTP Status Code: " + statusCode + " - " + msg + EOL + bytes.toString());
616     }
617   }
618
619   /**
620    * Writes the following information to the servlet log:
621    * <ol>
622    * <li>HTTP status code</li>
623    * <li>Message</li>
624    * </ol>
625    * @param msg Message to be logged
626    * @param statusCode Valid status code from javax.servlet.http.HttpServletResponse
627    */

628   protected void writeLog(String JavaDoc msg, int statusCode)
629   {
630     log("HTTP Status Code: " + statusCode + " - " + msg);
631   }
632
633   /**
634    * Invokes response.sendError setting an HTTP status code and optionally an error message
635    * as an HTML page.
636    * <p>If running in debug mode, also try to return a stack trace of the exception and
637    * and xml/xsl processor messages.</p>
638    * @param response Where to stream the exception to
639    * @param xse The wrapper which contains the exception and its HTTP status code
640    * @param debug Indicates whether to include stack trace, etc.
641    */

642   protected void displayException(HttpServletResponse response, ApplyXSLTException xse, boolean debug)
643   {
644     String JavaDoc mesg = xse.getMessage();
645     if (mesg == null)
646       mesg = "";
647     else mesg = "<B>" + mesg + "</B>";
648     StringTokenizer tokens = new StringTokenizer(mesg, EOL);
649     StringBuffer JavaDoc strBuf = new StringBuffer JavaDoc();
650     while (tokens.hasMoreTokens())
651       strBuf.append(tokens.nextToken() + EOL + "<BR>");
652     mesg = strBuf.toString();
653     if (debug)
654     {
655       ByteArrayOutputStream bytes = new ByteArrayOutputStream();
656       PrintWriter writer = new PrintWriter(bytes, true);
657       xse.getException().printStackTrace(writer);
658       mesg += " <PRE> " + bytes.toString() + " </PRE> ";
659     }
660     response.setContentType("text/html");
661     try
662     {
663       response.sendError(xse.getStatusCode(), mesg);
664     }
665     catch (IOException ioe)
666     {
667       System.err.println("IOException is occurring when sendError is called");
668     }
669   }
670
671   /**
672    * Mapping of HTTP request's user-Agent values to stylesheet media= values.
673    * <p>This mapping is defined by a file pointed to by the operational parameter "mediaURL" which can
674    * either contain a full URL or a path relative to the System's server.root /servlets directory.</p>
675    * @see #setMediaProps
676    * @see #getMedia
677    * @serial
678    */

679   protected OrderedProps ourMediaProps = null;
680
681   /**
682    * Returns a connection which respects the Accept-Language header of the HTTP request. This
683    * is useful when XSL files are internationalized for use with Web servers which respect this
684    * header.
685    * <p>For example, Apache 1.3.6 may be configured for multiviews. Under this configuration,
686    * requests for http://myhost/index.html would return http://myhost/index.html.fr to French browsers
687    * and http://myhost/index.html.en to English browsers.</p>
688    * @param url Location to connect to
689    * @param request Could contain an Accept-Language header
690    * @return An Accept-Language-enabled URL connection
691    * @see #getStylesheet
692    */

693   protected URLConnection JavaDoc toAcceptLanguageConnection(URL JavaDoc url, HttpServletRequest request)
694     throws Exception JavaDoc
695   {
696     URLConnection JavaDoc tempConnection = url.openConnection();
697     tempConnection.setRequestProperty("Accept-Language", request.getHeader("Accept-Language"));
698     return tempConnection;
699   }
700
701
702   /**
703    * Returns the XSL stylesheet URL associated with the specified XML document. If multiple XSL
704    * stylesheets are associated with the XML document, preference will be given to the stylesheet
705    * which contains an attribute name/value pair that corresponds to the specified attributeName
706    * and attributeValue.
707    * @param xmlSource XML XSLTInputSource to be searched for associated XSL stylesheets
708    * @param attributeName Attribute name to provide preferential matching
709    * @param attributeValue Attribute value to provide preferential matching
710    * @return The preferred XSL stylesheet URL, or null if no XSL stylesheet association is found
711    * @see #getStylesheet
712    */

713   public static String JavaDoc getXSLURLfromDoc(StreamSource xmlSource,
714                                         String JavaDoc attributeName,
715                                         String JavaDoc attributeValue,
716                                         TransformerFactory tFactory)
717   {
718     String JavaDoc tempURL = null, returnURL = null;
719     try
720     {
721       DocumentBuilderFactory JavaDoc dfactory = DocumentBuilderFactory.newInstance();
722       DocumentBuilder JavaDoc docBuilder = dfactory.newDocumentBuilder();
723       Node sourceTree = docBuilder.parse(xmlSource.getInputStream());
724       for(Node child=sourceTree.getFirstChild(); null != child; child=child.getNextSibling())
725       {
726         if(Node.PROCESSING_INSTRUCTION_NODE == child.getNodeType())
727         {
728           ProcessingInstruction pi = (ProcessingInstruction)child;
729           if(pi.getNodeName().equals("xml-stylesheet"))
730           {
731             PIA pia = new PIA(pi);
732             if("text/xsl".equals(pia.getAttribute("type")))
733             {
734               tempURL = pia.getAttribute("href");
735               String JavaDoc attribute = pia.getAttribute(attributeName);
736               if ((attribute != null) && (attribute.indexOf(attributeValue) > -1))
737                 return tempURL;
738               if (!"yes".equals(pia.getAttribute("alternate")))
739                 returnURL = tempURL;
740             }
741           }
742         }
743       }
744     }
745     catch(Exception JavaDoc saxExc)
746     {
747     }
748     return returnURL;
749   }
750
751  /**
752    * The attribute name in the <?xml-stylesheet> tag used in stylesheet selection.
753    */

754   protected static final String JavaDoc STYLESHEET_ATTRIBUTE = "media";
755
756   /**
757    * The HTTP Header used for matching the Stylesheet attribute via the
758    * media properties file selected.
759    */

760   protected static final String JavaDoc HEADER_NAME = "user-Agent";
761 }
762
763 /**
764  * Stores the keys and values from a file (similar to a properties file) and
765  * can return the first value which has a key contained in its string.
766  * File can have comment lines starting with '#" and for each line the entries are
767  * separated by tabs and '=' char.
768  */

769 class OrderedProps
770 {
771
772   /**
773    * Stores the Key and Values as an array of Strings
774    */

775   private Vector attVec = new Vector(15);
776
777   /**
778    * Constructor.
779    * @param inputStream Stream containing the properties file.
780    * @exception IOException Thrown if unable to read from stream
781    */

782   OrderedProps(InputStream inputStream)
783     throws IOException
784   {
785     BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
786     String JavaDoc currentLine, Key = null;
787     StringTokenizer currentTokens;
788     while ((currentLine = input.readLine()) != null)
789     {
790       currentTokens = new StringTokenizer(currentLine, "=\t\r\n");
791       if (currentTokens.hasMoreTokens()) Key = currentTokens.nextToken().trim();
792       if ((Key != null) && !Key.startsWith("#") && currentTokens.hasMoreTokens())
793       {
794         String JavaDoc temp[] = new String JavaDoc[2];
795         temp[0] = Key; temp[1] = currentTokens.nextToken().trim();
796         attVec.addElement(temp);
797       }
798     }
799   }
800
801   /**
802    * Iterates through the Key list and returns the first value for whose
803    * key the given string contains. Returns "unknown" if no key is contained
804    * in the string.
805    * @param s String being searched for a key.
806    * @return Value for key found in string, otherwise "unknown"
807    */

808   String JavaDoc getValue(String JavaDoc s)
809   {
810     int i, j = attVec.size();
811     for (i = 0; i < j; i++)
812     {
813       String JavaDoc temp[] = (String JavaDoc[]) attVec.elementAt(i);
814       if (s.indexOf(temp[0]) > -1)
815         return temp[1];
816     }
817     return "unknown";
818   }
819 }
820
821 /**
822  * Parses a processing instruction's (PI) attributes for easy retrieval.
823  */

824 class PIA
825 {
826
827   private Hashtable piAttributes = null;
828
829   /**
830    * Constructor.
831    * @param pi The processing instruction whose attributes are to be parsed
832    */

833   PIA(ProcessingInstruction pi)
834   {
835     piAttributes = new Hashtable();
836     StringTokenizer tokenizer = new StringTokenizer(pi.getNodeValue(), "=\"");
837     while(tokenizer.hasMoreTokens())
838     {
839       piAttributes.put(tokenizer.nextToken().trim(), tokenizer.nextToken().trim());
840     }
841   }
842
843   /**
844    * Returns value of specified attribute.
845    * @param name Attribute name
846    * @return Attribute value, or null if the attribute name does not exist
847    */

848   String JavaDoc getAttribute(String JavaDoc name)
849   {
850     return (String JavaDoc) piAttributes.get(name);
851   }
852 }
853
Popular Tags