| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999-2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, Lotus |
| * Development Corporation., http://www.lotus.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package servlet; |
| |
| import java.io.*; |
| import java.util.*; |
| import javax.servlet.*; |
| import javax.servlet.http.*; |
| import java.net.URL; |
| import java.net.MalformedURLException; |
| import java.net.URLConnection; |
| import javax.xml.transform.OutputKeys; |
| |
| import org.apache.xalan.templates.Constants; |
| import org.apache.xalan.templates.StylesheetRoot; |
| import org.apache.xalan.templates.OutputProperties; |
| // SAX2 Imports |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.Locator; |
| import org.xml.sax.helpers.XMLReaderFactory; |
| import org.xml.sax.ext.DeclHandler; |
| import org.xml.sax.ext.LexicalHandler; |
| import org.xml.sax.SAXNotRecognizedException; |
| import org.xml.sax.SAXNotSupportedException; |
| |
| import org.w3c.dom.*; |
| import javax.xml.transform.*; |
| import javax.xml.transform.stream.*; |
| import javax.xml.transform.sax.SAXTransformerFactory; |
| import org.apache.xalan.transformer.TransformerImpl; |
| import org.apache.xpath.objects.XObject; |
| import org.apache.xpath.objects.XString; |
| import org.apache.xalan.processor.*; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.helpers.XMLReaderFactory; |
| import org.xml.sax.helpers.XMLFilterImpl; |
| |
| /***************************************************************************************************** |
| * |
| * ApplyXSLT supplies the basic |
| * functions for transforming XML data using XSL stylesheets. |
| * |
| * @author Spencer Shepard (sshepard@us.ibm.com) |
| * @author R. Adam King (rak@us.ibm.com) |
| * @author Tom Rowe (trowe@us.ibm.com) |
| * @author Don Leslie (donald_leslie@lotus.com) |
| * |
| *****************************************************************************************************/ |
| |
| public class ApplyXSLT extends HttpServlet |
| { |
| |
| /** |
| * Operational parameters for this class. |
| * <p>Request-time values override init-time values which override class defaults.</p> |
| * @see #init |
| * @serial |
| */ |
| protected ApplyXSLTProperties ourDefaultParameters = null; |
| private boolean useDefaultTemplates = false; |
| private Templates defaultTemplates = null; |
| |
| /** |
| * String representing the end of line characters for the System. |
| */ |
| public final static String EOL = System.getProperty("line.separator"); |
| |
| /** |
| * String representing the file separator characters for the System. |
| */ |
| public final static String FS = System.getProperty("file.separator"); |
| |
| /** |
| * String representing the current directory for properties files. See init(). |
| */ |
| public final static String ROOT = System.getProperty("server.root"); |
| public static String CURRENTDIR; |
| |
| /** |
| * Initialize operational parameters from the configuration. |
| * @param config Configuration |
| * @exception ServletException Never thrown |
| */ |
| public void init(ServletConfig config) |
| throws ServletException |
| { |
| super.init(config); |
| // If the server.root property --see above-- is null, use current working directory |
| // as default location for media.properties. |
| if (ROOT != null) |
| CURRENTDIR= ROOT + FS + "servlets" + FS; |
| else |
| CURRENTDIR = System.getProperty("user.dir")+ FS; |
| |
| setDefaultParameters(config); |
| |
| setMediaProps(config.getInitParameter("mediaURL")); |
| String defaultXSL = config.getInitParameter("xslURL"); |
| try |
| { |
| if (defaultXSL !=null && defaultXSL.length() > 0) |
| compileXSL(defaultXSL); |
| } |
| catch (Exception e){} |
| } |
| |
| /** |
| * If a default setting exists for xslURL, create a Templates object |
| * for rapid transformations. |
| */ |
| protected void compileXSL(String defaultXSL) |
| throws TransformerConfigurationException |
| { |
| TransformerFactory tFactory = TransformerFactory.newInstance(); |
| defaultTemplates = tFactory.newTemplates(new StreamSource(defaultXSL)); |
| useDefaultTemplates = true; |
| } |
| |
| /** |
| * Sets the default parameters for the servlet from the configuration. |
| * Also sets required system properties until we figure out why servlet |
| * sometimess fails to read properties from properties files. |
| * @param config Configuration |
| */ |
| protected void setDefaultParameters(ServletConfig config) |
| { |
| ourDefaultParameters = new DefaultApplyXSLTProperties(config); |
| } |
| |
| /** |
| * Loads the media properties file specified by the given string. |
| * @param mediaURLstring Location of the media properties file. Can be either a full URL or a path relative |
| * to the System's server.root /servlets directory. If this parameter is null, |
| * server.root/servlets/media.properties will be used. |
| * @see ApplyXSL#CURRENTDIR |
| */ |
| protected void setMediaProps(String mediaURLstring) |
| { |
| if (mediaURLstring != null) |
| { |
| URL url = null; |
| try |
| { |
| url = new URL(mediaURLstring); |
| } |
| catch (MalformedURLException mue1) |
| { |
| try |
| { |
| url = new URL("file", "", CURRENTDIR + mediaURLstring); |
| } |
| catch (MalformedURLException mue2) |
| { |
| writeLog("Unable to find the media properties file based on parameter 'mediaURL' = " |
| + mediaURLstring, HttpServletResponse.SC_ACCEPTED, mue2); |
| url = null; |
| } |
| } |
| if (url != null) |
| { |
| try |
| { |
| ourMediaProps = new OrderedProps(url.openStream()); |
| } |
| catch (IOException ioe1) |
| { |
| writeLog("Exception occurred while opening media properties file: " + mediaURLstring + |
| ". Media table may be invalid.", HttpServletResponse.SC_ACCEPTED, ioe1); |
| } |
| } |
| } |
| else |
| { |
| String defaultProp = CURRENTDIR + "media.properties"; |
| try |
| { |
| ourMediaProps = new OrderedProps(new FileInputStream(defaultProp)); |
| } |
| catch (IOException ioe2) |
| { |
| writeLog("Default media properties file " + defaultProp + " not found.", |
| HttpServletResponse.SC_ACCEPTED, ioe2); |
| } |
| } |
| } |
| |
| public String getMedia(HttpServletRequest request) |
| { |
| return ourMediaProps.getValue(request.getHeader(HEADER_NAME)); |
| } |
| |
| // doPost removed for security reasons due to the possibility of sending |
| // unsecure XML and XSL XSLTInputSources through the request input stream |
| |
| /** |
| * HTTP Get method passed on to process(). |
| * @param request The request |
| * @param response The response |
| * @see #process |
| * @exception ServletException Never thrown |
| * @exception IOException Never thrown |
| */ |
| public void doGet (HttpServletRequest request, |
| HttpServletResponse response) |
| throws ServletException, IOException |
| { |
| try |
| { |
| TransformerFactory tFactory = TransformerFactory.newInstance(); |
| process(tFactory, request, response); |
| } |
| catch (Exception e) |
| { |
| } |
| } |
| |
| /** |
| * Coordinates applying an XSL stylesheet to XML data using operational parameters. |
| * <p>If successfully applied, the result tree will be streamed to the response object |
| * and the content type set according to the XSL stylesheet's <xsl:output> element(s).</p> |
| * <p>If there is a problem in parsing the XML/XSL or if there is a problem in applying |
| * the XSL to the XML, an exception will be streamed to the response object. The detail |
| * of the information returned in the response object will depend on whether we're |
| * running in debug mode or not.</p> |
| * @param processor implementation of TRaX processor |
| * @param request May contain information relevant to creating XML and XSL XSLTInputSource's |
| * @param response Where to write the transformation result |
| * @see #getDocument |
| * @see #getStylesheet |
| * @see #getContentType |
| * @see #displayException |
| * @see #setStylesheetParams |
| * @exception ServletException Never thrown |
| * @exception IOException Never thrown |
| */ |
| |
| public void process(TransformerFactory tFactory, |
| HttpServletRequest request, |
| HttpServletResponse response) |
| throws ServletException, IOException, SAXException |
| { |
| boolean debug = ourDefaultParameters.isDebug(request); |
| |
| long time = 0; |
| if (debug) |
| time = System.currentTimeMillis(); |
| |
| // Listener to be used for all reporting |
| ApplyXSLTListener listener = new ApplyXSLTListener(); |
| listener.out.println("debug is " + debug); |
| |
| Source xmlSource = null; |
| Source xslSource = null; |
| try |
| { |
| if ((xmlSource = getDocument(request, listener)) == null) |
| throw new ApplyXSLTException("getDocument() returned null", |
| new NullPointerException(), |
| response.SC_NOT_FOUND); |
| } |
| catch (ApplyXSLTException axe) |
| { |
| axe.appendMessage(EOL + "getDocument() resulted in ApplyXSLTException" + EOL |
| + listener.getMessage()); |
| if (debug) writeLog(axe); |
| displayException(response, axe, debug); |
| xmlSource = null; |
| } |
| // creating XSL Stylesheet |
| if (xmlSource != null) |
| { |
| try |
| { |
| if ((xslSource = getStylesheet(tFactory, request, xmlSource, listener)) == null) |
| throw new ApplyXSLTException("getStylesheet() returned null", |
| new NullPointerException(), |
| response.SC_NOT_FOUND); |
| |
| // Must "reset" xmlSource (a StreamSource) after looking for stylesheet PI |
| xmlSource = getDocument(request, listener); |
| } |
| catch (ApplyXSLTException axe) |
| { |
| axe.appendMessage(EOL + "getStylesheet() resulted in ApplyXSLTException" + EOL |
| + listener.getMessage()); |
| if (debug) writeLog(axe); |
| displayException(response, axe, debug); |
| xslSource = null; |
| } |
| // perform Transformation |
| |
| if (useDefaultTemplates) |
| { |
| try |
| { |
| listener.out.println("Using default templates"); |
| if (defaultTemplates == null) |
| { |
| listener.out.println("Must recompile default templates"); |
| defaultTemplates = tFactory.newTemplates(xslSource); |
| } |
| Transformer transformer = defaultTemplates.newTransformer(); |
| String contentType = null; |
| contentType = getContentType(defaultTemplates); |
| if (contentType != null); |
| response.setContentType(contentType); |
| |
| if (transformer instanceof TransformerImpl) |
| { |
| TransformerImpl transformerImpl = (TransformerImpl)transformer; |
| transformerImpl.setQuietConflictWarnings(ourDefaultParameters.isNoCW(request)); |
| } |
| |
| setStylesheetParams(transformer, request); |
| transformer.transform(xmlSource, new StreamResult(response.getOutputStream())); |
| |
| if (debug) |
| writeLog(listener.getMessage(), response.SC_OK); |
| |
| } |
| catch (Exception exc) |
| { |
| ApplyXSLTException axe = new ApplyXSLTException |
| ("Exception occurred during Transformation:" |
| + EOL + listener.getMessage() + EOL |
| + exc.getMessage(), |
| exc, |
| response.SC_INTERNAL_SERVER_ERROR); |
| if (debug) writeLog(axe); |
| displayException(response, axe, debug); |
| } |
| } |
| |
| else if ((xmlSource != null) && (xslSource != null)) |
| { |
| try |
| { |
| listener.out.println("Performing transformation..."); |
| Templates templates = tFactory.newTemplates(xslSource); |
| Transformer transformer = templates.newTransformer(); |
| |
| try |
| { |
| String contentType = null; |
| contentType = getContentType(templates); |
| if (contentType != null); |
| response.setContentType(contentType); |
| |
| if (transformer instanceof TransformerImpl) |
| { |
| TransformerImpl transformerImpl = (TransformerImpl)transformer; |
| transformerImpl.setQuietConflictWarnings(ourDefaultParameters.isNoCW(request)); |
| } |
| |
| setStylesheetParams(transformer, request); |
| transformer.transform(xmlSource, new StreamResult(response.getOutputStream())); |
| |
| if (debug) |
| writeLog(listener.getMessage(), response.SC_OK); |
| } |
| catch (Exception exc) |
| { |
| ApplyXSLTException axe = new ApplyXSLTException |
| ("Exception occurred during Transformation:" |
| + EOL + listener.getMessage() + EOL |
| + exc.getMessage(), |
| exc, |
| response.SC_INTERNAL_SERVER_ERROR); |
| if (debug) writeLog(axe); |
| displayException(response, axe, debug); |
| } |
| finally |
| { |
| // transformer.reset(); |
| } // end of try ... catch ... finally |
| } |
| catch (/*org.xml.sax.SAX*/Exception saxExc) |
| { |
| ApplyXSLTException axe = new ApplyXSLTException |
| ("Exception occurred during ctor/Transformation:" |
| + EOL + listener.getMessage() + EOL |
| + saxExc.getMessage(), |
| saxExc, |
| response.SC_INTERNAL_SERVER_ERROR); |
| if (debug) writeLog(axe); |
| displayException(response, axe, debug); |
| } // end of new try ... catch |
| } // end of if((stylesheetRoot != null) ... |
| if (debug) |
| { |
| time = System.currentTimeMillis() - time; |
| writeLog(" No Conflict Warnings = " + ourDefaultParameters.isNoCW(request) + |
| " Transformation time: " + time + " ms", response.SC_OK); |
| } |
| } |
| } |
| |
| /** |
| * Returns a Source object with the XML document to be transformed. Attempts will be make to create the |
| * Source object from the following: |
| * <ol> |
| * <li>A relative URL specified in the HTTP request's path information. This capability is intended |
| * for use by <b>servlet engines that map</b> some or all XML data to be processed at the server.</li> |
| * <li>A URL specified in the HTTP request's <code>URL=</code> parameter. This capability |
| * is intended for <b>clients wishing to selectively process</b> XML data at the server. For |
| * security reasons, this URL will be forced to the local IP host.</li> |
| * <li>The HTTP request's XML input stream. This capability is intended for use by chained servlets.</li> |
| * </ol> |
| * @param request client HTTPRequest object |
| * @param listener To record detailed parsing messages for possible return to requestor |
| * @return Source with XML document to be transformed, or null if the Source could not be located |
| * @exception ApplyXSLTException Thrown if exception occurs while handling request |
| */ |
| protected Source getDocument(HttpServletRequest request, |
| ApplyXSLTListener listener) |
| throws ApplyXSLTException |
| { |
| try |
| { |
| String xmlURL = null; |
| // document from PathInfo |
| if ((xmlURL = request.getPathInfo()) != null) |
| { |
| listener.out.println("Parsing XML Document from PathInfo: " + xmlURL); |
| return new StreamSource(new URL("http", ((DefaultApplyXSLTProperties) |
| ourDefaultParameters).getLocalHost(), |
| xmlURL.replace('\\', '/')).openStream()); |
| } |
| // document from Request parameter |
| if ((xmlURL = ourDefaultParameters.getXMLurl(request)) != null) |
| { |
| listener.out.println("Parsing XML Document from request parameter: " + xmlURL); |
| return new StreamSource(new URL(xmlURL).openStream()); |
| } |
| // document from chain |
| String contentType = request.getContentType(); |
| if ((contentType != null) && contentType.startsWith("text/xml")) |
| { |
| listener.out.println("Parsing XML Document from request chain"); |
| return new StreamSource(request.getInputStream()); |
| } |
| } |
| catch (IOException ioe) |
| { |
| throw new ApplyXSLTException(ioe, HttpServletResponse.SC_NOT_FOUND); |
| } |
| catch (Exception e) |
| { |
| throw new ApplyXSLTException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a Source object containing the stylesheet. Attempts will be make to obtain the stylesheet |
| * from the following sources: |
| * <ol> |
| * <li>A URL specified in the HTTP request's <code>xslURL=</code> parameter. For security reasons, |
| * this URL will be forced to the local IP host.</li> |
| * <li>A URL specified in the XML document xsl:stylesheet Processing Instruction. XML documents may contain |
| * Processing Instruction references to one or more stylesheets using the |
| * <a HREF="http://www.w3.org/TR/xml-stylesheet/>Associating Style Sheets with XML documents</a> |
| * W3C ecommendation. |
| * If the XML document does contain such references, a best match will be chosen based on the browser |
| * type making the request and the default association. This capability enables relationships to be |
| * defined between client capabilities and stylesheets capable of acting on these capabilities.</li> |
| * <li>A default stylesheet URL specified when the servlet is loaded. During init(), the servlet |
| * uses this xslURL startup parameter to create a Templates object, which is the used for transformations |
| * where no other stylesheet is designated.</li> |
| * </ol> |
| * @param request the client HTTP request, which may include an xslURL parameter |
| * @param xmlSource the XML document to be transformed |
| * @param listener To record detailed parsing messages for possible return to requestor |
| * @return Source, or null if the stylesheet could not be located. |
| * @see #getMedia |
| * @see #STYLESHEET_ATTRIBUTE |
| * @see #toAcceptLanguageConnection |
| * @exception ApplyXSLTException Thrown if exception occurs while locating the stylesheet |
| */ |
| protected Source getStylesheet(TransformerFactory tFactory, |
| HttpServletRequest request, |
| Source xmlSource, |
| ApplyXSLTListener listener) |
| throws ApplyXSLTException |
| { |
| try |
| { |
| //stylesheet URL from request |
| String xslURL = ((DefaultApplyXSLTProperties) ourDefaultParameters).getXSLRequestURL(request); |
| |
| if (xslURL != null) |
| { |
| listener.out.println("Parsing XSL Stylesheet Document from request parameter: " |
| + xslURL); |
| useDefaultTemplates = false; |
| } |
| else |
| { |
| // find stylesheet from XML Document, Media tag preference |
| SAXTransformerFactory stf = (SAXTransformerFactory)tFactory; |
| Source styleSource = |
| stf.getAssociatedStylesheet(xmlSource,getMedia(request), null, null); |
| if (styleSource != null) |
| { |
| listener.out.println("Parsing XSL Stylesheet from XML document stylesheet PI."); |
| useDefaultTemplates = false; |
| return styleSource; |
| } |
| |
| // Configuration Default |
| if ((xslURL = ourDefaultParameters.getXSLurl(null)) != null) |
| { |
| listener.out.println("Parsing XSL Stylesheet Document from configuration: " + xslURL); |
| useDefaultTemplates = true; |
| } |
| } |
| return new StreamSource(xslURL); |
| } |
| catch (IOException ioe) |
| { |
| throw new ApplyXSLTException(ioe, HttpServletResponse.SC_NOT_FOUND); |
| } |
| catch (Exception e) |
| { |
| throw new ApplyXSLTException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| } |
| } |
| |
| /** |
| * Returns the response content type specified by the media-type and encoding attributes of |
| * the <xsl:output> element(s) of the stylesheet. |
| * Default output property settings are used for any properties not set by the stylesheet. |
| * @param xslSourceRoot XSL Stylesheet to be examined for <xsl:output> elements. |
| * @return The response content type (MIME type and charset) of the stylesheet output |
| * @see #process |
| */ |
| public String getContentType(Templates templates) |
| { |
| Properties oprops = templates.getOutputProperties(); |
| String method = oprops.getProperty(OutputKeys.METHOD); |
| if (method == null) method = "xml"; // the default. |
| |
| Properties defoprops = null; |
| if (method.equals("html")) |
| defoprops = OutputProperties.getDefaultMethodProperties("html"); |
| else if (method.equals("text")) |
| defoprops = OutputProperties.getDefaultMethodProperties("text"); |
| else |
| defoprops = OutputProperties.getDefaultMethodProperties("xml"); |
| |
| String encoding = oprops.getProperty(OutputKeys.ENCODING); |
| if (encoding == null) |
| encoding = defoprops.getProperty(OutputKeys.ENCODING); |
| |
| String media = oprops.getProperty(OutputKeys.MEDIA_TYPE); |
| if (media == null) |
| media = defoprops.getProperty(OutputKeys.MEDIA_TYPE); |
| |
| return media + "; charset=" + encoding; |
| } |
| |
| |
| /** |
| * Defines and sets select top-level XSL stylesheet variables from the HTTP request, which |
| * can be evaluated using <xsl:param-variable>. The following variables will be |
| * automatically set: |
| * <dl> |
| * <dt><i>ParameterName</i></dt> |
| * <dd>Each non-reserved request parameter returned from request.getParameterNames(). If a |
| * parameter contains more than a single value, only the first value is available.</dd> |
| * <dt>servlet-RemoteAddr</dt> |
| * <dd>Contains String output from request.getRemoteAddr(), which is the IP address |
| * of the client machine.</dd> |
| * <dt>servlet-RemoteHost</dt> |
| * <dd>Contains String output from request.getRemoteHost(), which is the host name |
| * of the client machine.</dd> |
| * <dt>servlet-RemoteUser</dt> |
| * <dd>Contains String output from request.getRemoteUser(), which was the user name |
| * accepted by the server to grant access to this servlet.</dd> |
| * <dt>servlet-Request</dt> |
| * <dd>Contains the request object.</dd> |
| * </dl> |
| * @param xslprocessor Where to register parameters to be set |
| * @param request Provides access to all meaningful parameters to set |
| * @see #process |
| */ |
| public void setStylesheetParams(Transformer transformer, HttpServletRequest request) |
| { |
| Enumeration paramNames = request.getParameterNames(); |
| while (paramNames.hasMoreElements()) |
| { |
| String paramName = (String) paramNames.nextElement(); |
| try |
| { |
| String[] paramVals = request.getParameterValues(paramName); |
| if (paramVals != null) |
| transformer.setParameter(paramName, new XString(paramVals[0])); |
| |
| } |
| catch (Exception e) |
| { |
| } |
| } |
| try |
| { |
| transformer.setParameter("servlet-RemoteAddr", new XString(request.getRemoteAddr())); |
| |
| } |
| catch (Exception e) |
| { |
| } |
| try |
| { |
| transformer.setParameter("servlet-RemoteHost", new XString(request.getRemoteHost())); |
| |
| } |
| catch (Exception e) |
| { |
| } |
| try |
| { |
| transformer.setParameter("servlet-RemoteUser", new XString(request.getRemoteUser())); |
| |
| } |
| catch (Exception e) |
| { |
| } |
| } |
| |
| |
| /** |
| * Writes the following information to the servlet log: |
| * <ol> |
| * <li>HTTP status code</li> |
| * <li>Message</li> |
| * <li>Stack trace</li> |
| * </ol> |
| * @param axe Contains valid HTTP status code, message, and stack trace (optional) |
| */ |
| protected void writeLog(ApplyXSLTException axe) |
| { |
| writeLog(axe.getMessage(), axe.getStatusCode(), axe.getException()); |
| } |
| |
| /** |
| * Writes the following information to the servlet log: |
| * <ol> |
| * <li>HTTP status code</li> |
| * <li>Message</li> |
| * <li>Stack trace</li> |
| * </ol> |
| * @param msg Message to be logged |
| * @param statusCode Valid status code from javax.servlet.http.HttpServletResponse |
| * @param t Used to generate stack trace (may be =null to suppress stack trace) |
| */ |
| protected void writeLog(String msg, int statusCode, Throwable t) |
| { |
| if (t == null) |
| writeLog(msg, statusCode); |
| else |
| { |
| ByteArrayOutputStream bytes = new ByteArrayOutputStream(); |
| PrintWriter writer = new PrintWriter(bytes, true); |
| System.out.println("Exception is " + t.getClass().getName()); |
| t.printStackTrace(writer); |
| log("HTTP Status Code: " + statusCode + " - " + msg + EOL + bytes.toString()); |
| } |
| } |
| |
| /** |
| * Writes the following information to the servlet log: |
| * <ol> |
| * <li>HTTP status code</li> |
| * <li>Message</li> |
| * </ol> |
| * @param msg Message to be logged |
| * @param statusCode Valid status code from javax.servlet.http.HttpServletResponse |
| */ |
| protected void writeLog(String msg, int statusCode) |
| { |
| log("HTTP Status Code: " + statusCode + " - " + msg); |
| } |
| |
| /** |
| * Invokes response.sendError setting an HTTP status code and optionally an error message |
| * as an HTML page. |
| * <p>If running in debug mode, also try to return a stack trace of the exception and |
| * and xml/xsl processor messages.</p> |
| * @param response Where to stream the exception to |
| * @param xse The wrapper which contains the exception and its HTTP status code |
| * @param debug Indicates whether to include stack trace, etc. |
| */ |
| protected void displayException(HttpServletResponse response, ApplyXSLTException xse, boolean debug) |
| { |
| String mesg = xse.getMessage(); |
| if (mesg == null) |
| mesg = ""; |
| else mesg = "<B>" + mesg + "</B>"; |
| StringTokenizer tokens = new StringTokenizer(mesg, EOL); |
| StringBuffer strBuf = new StringBuffer(); |
| while (tokens.hasMoreTokens()) |
| strBuf.append(tokens.nextToken() + EOL + "<BR>"); |
| mesg = strBuf.toString(); |
| if (debug) |
| { |
| ByteArrayOutputStream bytes = new ByteArrayOutputStream(); |
| PrintWriter writer = new PrintWriter(bytes, true); |
| xse.getException().printStackTrace(writer); |
| mesg += " <PRE> " + bytes.toString() + " </PRE> "; |
| } |
| response.setContentType("text/html"); |
| try |
| { |
| response.sendError(xse.getStatusCode(), mesg); |
| } |
| catch (IOException ioe) |
| { |
| System.err.println("IOException is occurring when sendError is called"); |
| } |
| } |
| |
| /** |
| * Mapping of HTTP request's user-Agent values to stylesheet media= values. |
| * <p>This mapping is defined by a file pointed to by the operational parameter "mediaURL" which can |
| * either contain a full URL or a path relative to the System's server.root /servlets directory.</p> |
| * @see #setMediaProps |
| * @see #getMedia |
| * @serial |
| */ |
| protected OrderedProps ourMediaProps = null; |
| |
| /** |
| * Returns a connection which respects the Accept-Language header of the HTTP request. This |
| * is useful when XSL files are internationalized for use with Web servers which respect this |
| * header. |
| * <p>For example, Apache 1.3.6 may be configured for multiviews. Under this configuration, |
| * requests for http://myhost/index.html would return http://myhost/index.html.fr to French browsers |
| * and http://myhost/index.html.en to English browsers.</p> |
| * @param url Location to connect to |
| * @param request Could contain an Accept-Language header |
| * @return An Accept-Language-enabled URL connection |
| * @see #getStylesheet |
| */ |
| protected URLConnection toAcceptLanguageConnection(URL url, HttpServletRequest request) |
| throws Exception |
| { |
| URLConnection tempConnection = url.openConnection(); |
| tempConnection.setRequestProperty("Accept-Language", request.getHeader("Accept-Language")); |
| return tempConnection; |
| } |
| |
| |
| /** |
| * Returns the XSL stylesheet URL associated with the specified XML document. If multiple XSL |
| * stylesheets are associated with the XML document, preference will be given to the stylesheet |
| * which contains an attribute name/value pair that corresponds to the specified attributeName |
| * and attributeValue. |
| * @param xmlSource XML XSLTInputSource to be searched for associated XSL stylesheets |
| * @param attributeName Attribute name to provide preferential matching |
| * @param attributeValue Attribute value to provide preferential matching |
| * @return The preferred XSL stylesheet URL, or null if no XSL stylesheet association is found |
| * @see #getStylesheet |
| */ |
| /* public static String getXSLURLfromDoc(StreamSource xmlSource, |
| String attributeName, |
| String attributeValue, |
| TransformerFactory tFactory) |
| { |
| String tempURL = null, returnURL = null; |
| try |
| { |
| DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); |
| DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); |
| Node sourceTree = docBuilder.parse(xmlSource.getInputStream()); |
| for(Node child=sourceTree.getFirstChild(); null != child; child=child.getNextSibling()) |
| { |
| if(Node.PROCESSING_INSTRUCTION_NODE == child.getNodeType()) |
| { |
| ProcessingInstruction pi = (ProcessingInstruction)child; |
| if(pi.getNodeName().equals("xml-stylesheet")) |
| { |
| PIA pia = new PIA(pi); |
| if("text/xsl".equals(pia.getAttribute("type"))) |
| { |
| tempURL = pia.getAttribute("href"); |
| String attribute = pia.getAttribute(attributeName); |
| if ((attribute != null) && (attribute.indexOf(attributeValue) > -1)) |
| return tempURL; |
| if (!"yes".equals(pia.getAttribute("alternate"))) |
| returnURL = tempURL; |
| } |
| } |
| } |
| } |
| } |
| catch(Exception saxExc) |
| { |
| } |
| return returnURL; |
| } |
| */ |
| /** |
| * The attribute name in the <?xml-stylesheet> tag used in stylesheet selection. |
| */ |
| protected static final String STYLESHEET_ATTRIBUTE = "media"; |
| |
| /** |
| * The HTTP Header used for matching the Stylesheet attribute via the |
| * media properties file selected. |
| */ |
| protected static final String HEADER_NAME = "user-Agent"; |
| } |
| |
| /** |
| * Stores the keys and values from a file (similar to a properties file) and |
| * can return the first value which has a key contained in its string. |
| * File can have comment lines starting with '#" and for each line the entries are |
| * separated by tabs and '=' char. |
| */ |
| class OrderedProps |
| { |
| |
| /** |
| * Stores the Key and Values as an array of Strings |
| */ |
| private Vector attVec = new Vector(15); |
| |
| /** |
| * Constructor. |
| * @param inputStream Stream containing the properties file. |
| * @exception IOException Thrown if unable to read from stream |
| */ |
| OrderedProps(InputStream inputStream) |
| throws IOException |
| { |
| BufferedReader input = new BufferedReader(new InputStreamReader(inputStream)); |
| String currentLine, Key = null; |
| StringTokenizer currentTokens; |
| while ((currentLine = input.readLine()) != null) |
| { |
| currentTokens = new StringTokenizer(currentLine, "=\t\r\n"); |
| if (currentTokens.hasMoreTokens()) Key = currentTokens.nextToken().trim(); |
| if ((Key != null) && !Key.startsWith("#") && currentTokens.hasMoreTokens()) |
| { |
| String temp[] = new String[2]; |
| temp[0] = Key; temp[1] = currentTokens.nextToken().trim(); |
| attVec.addElement(temp); |
| } |
| } |
| } |
| |
| /** |
| * Iterates through the Key list and returns the first value for whose |
| * key the given string contains. Returns "unknown" if no key is contained |
| * in the string. |
| * @param s String being searched for a key. |
| * @return Value for key found in string, otherwise "unknown" |
| */ |
| String getValue(String s) |
| { |
| int i, j = attVec.size(); |
| for (i = 0; i < j; i++) |
| { |
| String temp[] = (String[]) attVec.elementAt(i); |
| if (s.indexOf(temp[0]) > -1) |
| return temp[1]; |
| } |
| return "unknown"; |
| } |
| } |
| |
| /** |
| * Parses a processing instruction's (PI) attributes for easy retrieval. |
| */ |
| class PIA |
| { |
| |
| private Hashtable piAttributes = null; |
| |
| /** |
| * Constructor. |
| * @param pi The processing instruction whose attributes are to be parsed |
| */ |
| PIA(ProcessingInstruction pi) |
| { |
| piAttributes = new Hashtable(); |
| StringTokenizer tokenizer = new StringTokenizer(pi.getNodeValue(), "=\""); |
| while(tokenizer.hasMoreTokens()) |
| { |
| piAttributes.put(tokenizer.nextToken().trim(), tokenizer.nextToken().trim()); |
| } |
| } |
| |
| /** |
| * Returns value of specified attribute. |
| * @param name Attribute name |
| * @return Attribute value, or null if the attribute name does not exist |
| */ |
| String getAttribute(String name) |
| { |
| return (String) piAttributes.get(name); |
| } |
| } |