Building XslServlet

   

Building XslServlet

XslServlet and XslServletLiaisonImpl perform all the work of calling the XSLT processor.

XslServlet

Listing 8.1 is XslServlet , your specialized HttpServlet . It replaces doGet() and doPost() with its own version. The new methods have an additional parameter of type XslServletLiaison .

Listing 8.1 XslServlet.java
 package com.psol.pesticide; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class XslServlet    extends HttpServlet {    public void doGet(HttpServletRequest request,                      HttpServletResponse response)       throws ServletException, IOException    {       XslServletLiaisonImpl liaison =          new XslServletLiaisonImpl(getClass(),request);       doGet(request,response,liaison);       liaison.writeResponse(response);    }    public void doGet(HttpServletRequest request,                      HttpServletResponse response,                      XslServletLiaison liaison)       throws ServletException, IOException    {       response.sendError(HttpServletResponse.SC_BAD_REQUEST);    }    public void doPost(HttpServletRequest request,                       HttpServletResponse response)       throws ServletException, IOException    {       XslServletLiaisonImpl liaison =          new XslServletLiaisonImpl(getClass(),request);       doPost(request,response,liaison);       liaison.writeResponse(response);    }    public void doPost(HttpServletRequest request,                       HttpServletResponse response,                       XslServletLiaison liaison)       throws ServletException, IOException    {       response.sendError(HttpServletResponse.SC_BAD_REQUEST);    } } 

In answer to an HTTP request ( GET or POST ), the servlet creates an XslServletLiaisonImpl , passes the request to the specialized doGet() or doPost() , and uses the liaison to write the following response:

 public void doGet(HttpServletRequest request,                     HttpServletResponse response)      throws ServletException, IOException   {      XslServletLiaisonImpl liaison =         new XslServletLiaisonImpl(getClass(),request);      doGet(request,response,liaison);      liaison.writeResponse(response);   } 

XslServletLiaison

The declaration for XslServletLiaison is shown in Listing 8.2. It enables the servlet to communicate with the XSL processor. The main methods are as follows :

  • getWriter() ”Returns the Writer for the servlet to write the XML document. It replaces HttpServletResponse.getWriter() .

  • getXSL() and setXSL() ”Select the XSL style sheet that will be applied.

  • getSkin() ”Returns the servlet's skin, which is described in the next section.

Listing 8.2 XslServletLiaison.java
 package com.psol.pesticide; import java.io.*; public interface XslServletLiaison {    public XslWriter getWriter()       throws IOException;    public File getXSL();    public void setXSL(File xsl);    public String getSkin(); } 

Servlet Skins

XslServletLiaison must select the appropriate style before applying it. Experience shows that the most flexible solution is to extract a reference to the style sheet from the URL. However, it is not safe to pass it directly as a URL parameter, such as

http://catwoman.pineapplesoft.com/buglist?xsl=xsl/ buglist .xsl

because hackers can forge URLs that point to their XSL files. In other words, it enables them to run their own code (their style sheet) on your server:

 http://catwoman.pineapplesoft.com/buglist? xsl=http://www.hacker.com/ graphics/ccc.gif malign-style-sheet.xsl 

Instead, pass a shorter reference in the URL and turn into a safe file path on the server. In this project, the shorter reference is called a skin. The skin is simply a generic name for a given look and feel.

For example, the following URLs respectively apply the cool and fast skins to the buglist servlet:

 http://catwoman.pineapplesoft.com/buglist/cool   http://catwoman.pineapplesoft.com/buglist/fast 

Tip

The alternatives to extracting the style sheet from the URL are

  • A configuration file, which is less flexible. In particular, it is more difficult to provide the user with different links, such as a graphic-heavy ( cool ) and text-only ( fast ) versions of the same page.

  • Having the servlet explicitly call setXSL() , which creates a dependency between the designer and the programmer ”precisely what we try to avoid.


XslServletLiaisonImpl maps the skin ( cool ) to a file. It builds the filename by concatenating the skin to the servlet classname:

 // extract the "skin" from the URL   String pathInfo = request.getPathInfo();   if(null != pathInfo)   {      StringTokenizer tokenizer =         new StringTokenizer(pathInfo,"/",false);      if(tokenizer.hasMoreTokens())         skin = tokenizer.nextToken();   }   // turn the skin in the path to the style sheet   if(null != skin)      if(skin.equals("none"))         return;      else         xsl = new File("stylesheet",skin);   else      xsl = new File("stylesheet");   StringTokenizer tokenizer =      new StringTokenizer(clasz.getName(),".",false);   while(tokenizer.hasMoreTokens())      if(tokenizer.countTokens() == 1)         xsl = new File(xsl,tokenizer.nextToken() + ".xsl");      else       xsl = new File(xsl,tokenizer.nextToken()); 

As you can see, the skin none is not converted to a filename. none returns the raw XML file (applying no XSL style sheet). This is useful for debugging.

The following are several advantages of skins:

  • The style sheet is guaranteed to be a local file, which minimizes the chances of a hacker substituting a rogue style sheet.

  • Different servlets have different style sheets, but all the style sheets are grouped by the look and feel, or skin, that they implement.

  • The servlet can always use setXSL() for special cases.

Tip

Why use a special skin name, such as none , for raw XML? Why not reserve it for the empty skin, as in the following:

http://catwoman.pineapplesoft.com/buglist

In practice, it is best to use a special name because visitors might forget the skin when typing the URL. The empty skin should be reserved to a default style sheet rather than raw XML.


XslServletLiaisonImpl

Listing 8.3 is XslServletLiaisonImpl , the default implementation of XslServletLiaison using Xalan 1.0. If you elect another XSL processor, you must provide an implementation of XslServletLiaison for that processor.

Listing 8.3 XslServletLiaisonImpl.java
 package com.psol.pesticide; import java.io.*; import java.util.*; import org.xml.sax.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.xalan.xslt.*; public class XslServletLiaisonImpl    implements XslServletLiaison {    protected String skin = null;    protected File xsl = null;    protected ByteArrayOutputStream ostream = null;    protected XslWriter writer = null;    protected static Dictionary stylesheets = new Hashtable();    public XslServletLiaisonImpl(Class clasz,                                 HttpServletRequest request)    {       // extract the "skin" from the path information       String pathInfo = request.getPathInfo();       if(null != pathInfo)       {          StringTokenizer tokenizer =             new StringTokenizer(pathInfo,"/",false);          if(tokenizer.hasMoreTokens())             skin = tokenizer.nextToken();       }       // turn the skin in the path to the style sheet       if(null != skin)          if(skin.equals("none"))             return;          else             xsl = new File("stylesheet",skin);       else          xsl = new File("stylesheet");       StringTokenizer tokenizer =          new StringTokenizer(clasz.getName(),".",false);       while(tokenizer.hasMoreTokens())          if(tokenizer.countTokens() == 1)             xsl = new File(xsl,tokenizer.nextToken() + ".xsl");          else             xsl = new File(xsl,tokenizer.nextToken());    }    public XslWriter getWriter()    {       if(null == writer)       {          ostream = new ByteArrayOutputStream();          writer = new XslWriter(ostream);       }       return writer;    }    public File getXSL()    {       return xsl;    }    public void setXSL(File xsl)    {       this.xsl = xsl;    }    public String getSkin()    {       return skin;    }    protected class Struct    {       public long lastModified;       public StylesheetRoot stylesheet;       public Struct(long lastModified,StylesheetRoot stylesheet)       {          this.lastModified = lastModified;          this.stylesheet = stylesheet;       }    }    protected void writeStyledXml(InputStream istream,                                  HttpServletResponse response)       throws SAXException, ServletException, IOException    {       XSLTProcessor processor =          XSLTProcessorFactory.getProcessor();       // deal with precompiled style sheets       Struct s = (Struct)stylesheets.get(xsl);       if(null == s           s.lastModified < xsl.lastModified())       {          XSLTInputSource source =             new XSLTInputSource(new FileInputStream(xsl));          s = new Struct(xsl.lastModified(),                         processor.processStylesheet(source));          stylesheets.put(xsl,s);       }       else          processor.setStylesheet(s.stylesheet);       // set the content-type       String ct = s.stylesheet.getOutputMediaType(),              cs = s.stylesheet.getOutputEncoding();       if(null == ct)       {          if(s.stylesheet.isOutputMethodSet())          {             String method = s.stylesheet.getOutputMethod();             if(method.equalsIgnoreCase("xml"))                ct = "text/xml";             else if(method.equalsIgnoreCase("html"))                ct = "text/html";             else if(method.equalsIgnoreCase("text"))                ct = "text/plain";             else                throw new ServletException("Unknown method");          }          else             ct = "text/xml";       }       if(null != cs)          ct += "; charset=\ "" + cs + "\ "";       response.setContentType(ct);       // transform and write the result       XSLTInputSource source = new XSLTInputSource(istream);       XSLTResultTarget target =          new XSLTResultTarget(response.getOutputStream());       processor.process(source,null,target);    }    protected void writeRawXml(InputStream istream,                               HttpServletResponse response)       throws IOException    {       response.setContentType("text/xml");       OutputStream ostream = response.getOutputStream();       int c = istream.read();       while(-1 != c)       {          ostream.write(c);          c = istream.read();       }    }    public void writeResponse(HttpServletResponse response)       throws IOException, ServletException    {       if(null != writer)          writer.flush();       if(null == ostream  0 == ostream.size())          return;       writer.flush();       InputStream istream =          new ByteArrayInputStream(ostream.toByteArray());       if(null == xsl)          writeRawXml(istream,response);       else          try          {             writeStyledXml(istream,response);          }          catch(SAXException e)          {             throw new ServletException(e.getMessage());          }    } } 

You saw how the constructor selects the style sheet in the previous section. writeResponse() is called by XslServlet to perform the XSL transformation. It then delegates the actual work to writeRawXml() and writeStyledXml() .

writeStyledXml() is the method that calls the XSL processor. It takes advantage of Xalan precompiled style sheets, and it won't reread a style sheet unless it has been modified:

 // deal with precompiled style sheets   Struct s = (Struct)stylesheets.get(xsl);   if(null == s       s.lastModified < xsl.lastModified())   {      XSLTInputSource source =         new XSLTInputSource(new FileInputStream(xsl));      s = new Struct(xsl.lastModified(),                     processor.processStylesheet(source));      stylesheets.put(xsl,s);   }   else      processor.setStylesheet(s.stylesheet); 

The method also sets the content type, according to the media type and character set selected in the style sheet:

 // set the content-type   String ct = s.stylesheet.getOutputMediaType(),          cs = s.stylesheet.getOutputEncoding();   if(null == ct)   {      if(s.stylesheet.isOutputMethodSet())      {         String method = s.stylesheet.getOutputMethod();         if(method.equalsIgnoreCase("xml"))            ct = "text/xml";         else if(method.equalsIgnoreCase("html"))            ct = "text/html";         else if(method.equalsIgnoreCase("text"))            ct = "text/plain";         else            throw new ServletException("Unknown method");      }      else         ct = "text/xml";   }   if(null != cs)      ct += "; charset=\ "" + cs + "\ "";   response.setContentType(ct); 

Finally, the method calls Xalan to perform the transformation:

 // transform and write the result   XSLTInputSource source = new XSLTInputSource(istream);   XSLTResultTarget target =      new XSLTResultTarget(response.getOutputStream()); processor.process(source,null,target); 
   


Applied XML Solutions
Applied XML Solutions
ISBN: 0672320541
EAN: 2147483647
Year: 1999
Pages: 142

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net