forrest-svn mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From thors...@apache.org
Subject svn commit: r736998 - in /forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper: ContractHandler.java XSLContractHelper.java
Date Fri, 23 Jan 2009 11:00:17 GMT
Author: thorsten
Date: Fri Jan 23 03:00:16 2009
New Revision: 736998

URL: http://svn.apache.org/viewvc?rev=736998&view=rev
Log:
Due to perfomance consideration switching from StAX to SAX processing in the contracts. This
change in combination with a couple recent changes has enhanced the response time notable

Added:
    forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/ContractHandler.java
Modified:
    forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/XSLContractHelper.java

Added: forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/ContractHandler.java
URL: http://svn.apache.org/viewvc/forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/ContractHandler.java?rev=736998&view=auto
==============================================================================
--- forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/ContractHandler.java
(added)
+++ forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/ContractHandler.java
Fri Jan 23 03:00:16 2009
@@ -0,0 +1,154 @@
+package org.apache.forrest.dispatcher.impl.helper;
+
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class ContractHandler extends EchoHandler {
+
+  private boolean recording = false;
+  private HashMap<String, String> map;
+  private HashSet<String> mapTrigger;
+  private String name = "", usage = "", description = "";
+  private boolean descriptionRecord;
+  private boolean usageRecord;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getUsage() {
+    return usage;
+  }
+
+  public void setUsage(String usage) {
+    this.usage = usage;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public ContractHandler(String encoding) {
+    super(encoding);
+    map = new HashMap<String, String>();
+    mapTrigger = new HashSet<String>();
+    descriptionRecord = false;
+    usageRecord = false;
+  }
+
+  public void startElement(String uri, String loc, String raw, Attributes attrs)
+      throws SAXException {
+    if (uri.equals(Captions.NS) && loc.equals(Captions.CONTRACT_ELEMENT)){
+      for (int i = 0; i < attrs.getLength(); i++) {
+        String aName = attrs.getLocalName(i); // Attr name
+        if (aName.equals(Captions.CONTRACT_NAME_ATT)) {
+          name = attrs.getValue(i);
+        }
+      }
+    } else if (raw.equals(Captions.DESCRIPTION_ELEMENT)){
+      descriptionRecord = true;
+    } else if (raw.equals(Captions.USAGE_ELEMENT)){
+      usageRecord = true;
+    }else if (uri.equals(Captions.NS_XSL) && loc.equals("stylesheet")) {
+      recording = true;
+    }
+
+    if (recording) {
+      String prefix = extractPrefix(raw);
+      emit(lineEnd + "<" + raw);
+      if (uri != null && !uri.equals("")) {
+        if (prefix != null) {
+          if (!map.containsKey(prefix)) {
+            emit(" xmlns:" + prefix + "=\"" + uri + "\"");
+            map.put(prefix, uri);
+            mapTrigger.add(raw);
+          }
+        } else {
+          emit(" xmlns=\"" + uri + "\"");
+        }
+      }
+      if (attrs != null) {
+        for(int i=attrs.getLength()-1;i>=0;i--){
+          String qName = attrs.getQName(i);
+          String localName = extractSufix(qName);
+          prefix = extractPrefix(qName);
+          if ( null == prefix || (null != prefix && !prefix.equals("xmlns"))) {
+            writeAttribute(attrs.getValue(i), qName);
+          }else if (null != prefix && prefix.equals("xmlns") && !map.containsKey(localName)){
+            writeAttribute(attrs.getValue(i), qName);
+          }
+        }
+      }
+        emit(">");
+    }
+  }
+
+  private void writeAttribute(String localValue, String qName)
+      throws SAXException {
+    emit(" ");
+    emit(qName);
+    emit("=\"");
+    char[] value = localValue.toCharArray();
+    characters(value, 0, value.length);
+    emit("\"");
+  }
+
+  public void endElement(String uri, String loc, String raw)
+      throws SAXException {
+    if (raw.equals(Captions.DESCRIPTION_ELEMENT)){
+      descriptionRecord = false;
+    }else if (raw.equals(Captions.USAGE_ELEMENT)){
+      usageRecord = false;
+    }
+    if (recording) {
+      String prefix = extractPrefix(raw);
+      if (prefix != null && map.containsKey(prefix) && mapTrigger.contains(raw))
{
+        map.remove(prefix);
+        mapTrigger.remove(raw);
+      }
+        super.endElement(uri, loc, raw);
+    }
+    if (uri.equals("http://www.w3.org/1999/XSL/Transform")
+        && loc.equals("stylesheet")) {
+      endPrefixMapping(extractPrefix(raw));
+      recording = false;
+    }
+  }
+
+  public void characters(char ch[], int start, int length) throws SAXException {
+    if (recording) {
+      super.characters(ch, start, length);
+    }else if (descriptionRecord){
+      description += cleanCharacters(ch, start, length);
+    }else if (usageRecord){
+      usage += cleanCharacters(ch, start, length);
+    }
+  }
+
+  /**
+   * @param ch
+   * @param start
+   * @param length
+   */
+  private String cleanCharacters(char[] ch, int start, int length) {
+    StringBuffer buffer = new StringBuffer();
+    for (int i = 0; i < length; i++) {
+      char c = ch[start + i];
+      buffer.append(c);
+    }
+    return StringEscapeUtils.escapeXml(buffer.toString().trim());
+  }
+
+}

Modified: forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/XSLContractHelper.java
URL: http://svn.apache.org/viewvc/forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/XSLContractHelper.java?rev=736998&r1=736997&r2=736998&view=diff
==============================================================================
--- forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/XSLContractHelper.java
(original)
+++ forrest/branches/dispatcher_rewrite/plugins/org.apache.forrest.plugin.internal.dispatcher/src/java/org/apache/forrest/dispatcher/impl/helper/XSLContractHelper.java
Fri Jan 23 03:00:16 2009
@@ -20,18 +20,16 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
 import java.util.Iterator;
 import java.util.Map;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.stream.XMLEventWriter;
-import javax.xml.stream.XMLStreamConstants;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import javax.xml.stream.XMLStreamWriter;
-import javax.xml.stream.util.XMLEventAllocator;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
@@ -40,20 +38,61 @@
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.stream.StreamSource;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.forrest.dispatcher.exception.ContractException;
 import org.apache.forrest.dispatcher.impl.XSLContract;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
 
-public class XSLContractHelper extends Loggable{
+public class XSLContractHelper extends Loggable {
 
   private Transformer transformer = null;
   private TransformerFactory transFact = null;
-  private StAX stax = null;
+  private SAXParser parser;
+  private DocumentBuilder builder;
+  private String name;
+  
 
-  public XSLContractHelper(TransformerFactory transformerFactory,StAX stax) {
+  /**
+   * @return the name of the contract
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * @param name the name to set of the contract
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  /**
+   * Create a new instance of the contract helper
+   * with the transformer factory we want to use.
+   * <p>
+   * We are using the parameter approach to optimize performance. 
+   * @param transformerFactory the transformer factory that we should use for this helper
class
+   * @throws ContractException
+   * @throws ParserConfigurationException 
+   * @throws SAXNotSupportedException 
+   * @throws SAXNotRecognizedException 
+   */
+  public XSLContractHelper(TransformerFactory transformerFactory)
+      throws ContractException, SAXNotRecognizedException, SAXNotSupportedException, ParserConfigurationException
{
     this.transFact = transformerFactory;
-    this.stax = stax;
+    SAXParserFactory factory = SAXParserFactory.newInstance();
+    factory.setNamespaceAware(true);
+    factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
+    try {
+      parser = factory.newSAXParser();
+      builder = DocumentBuilderFactory.newInstance()
+      .newDocumentBuilder();
+    } catch (Exception e) {
+      throw new ContractException(e);
+    }
   }
 
   /**
@@ -65,12 +104,14 @@
    * @param allowXmlProperties
    *          whether or not we want to allow xml properties
    * @throws TransformerConfigurationException
-   * @throws ParserConfigurationException 
-   * @throws IOException 
-   * @throws SAXException 
+   * @throws ParserConfigurationException
+   * @throws IOException
+   * @throws SAXException
    */
-  public void prepareTransformation(Source xslSource, boolean allowXmlProperties, Map<String,
Object> params)
-      throws TransformerConfigurationException, ParserConfigurationException, SAXException,
IOException {
+  public void prepareTransformation(Source xslSource,
+      boolean allowXmlProperties, Map<String, Object> params)
+      throws TransformerConfigurationException, ParserConfigurationException,
+      SAXException, IOException {
     // prepare transformation
     transformer = transFact.newTransformer(xslSource);
     transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
@@ -79,30 +120,30 @@
     // set errorListener
     transformer.setErrorListener(new LoggingErrorListener(log));
     // do we allow xml properties?
-    if(allowXmlProperties){
-      DocumentBuilder builder = DocumentBuilderFactory.newInstance()
-      .newDocumentBuilder();
+    if (allowXmlProperties) {
       for (Iterator<String> iter = params.keySet().iterator(); iter.hasNext();) {
         String key = iter.next();
         Class<String> string = String.class;
         Object value = params.get(key);
-        if (!string.isInstance(value)){
-         if(log.isDebugEnabled()){
-           log.debug( new String((byte[])value));
-         }
-          BufferedInputStream valueStream = new BufferedInputStream(new ByteArrayInputStream((byte[])
value));
-          transformer.setParameter(key, builder.parse(valueStream).getFirstChild());
-        }else{
-          transformer.setParameter(key,value);
+        if (!string.isInstance(value)) {
+          if (log.isDebugEnabled()) {
+            log.debug(new String((byte[]) value));
+          }
+          BufferedInputStream valueStream = new BufferedInputStream(
+              new ByteArrayInputStream((byte[]) value));
+          transformer.setParameter(key, builder.parse(valueStream)
+              .getFirstChild());
+        } else {
+          transformer.setParameter(key, value);
         }
       }
-    }else{
+    } else {
       for (Iterator<String> iter = params.keySet().iterator(); iter.hasNext();) {
         String key = iter.next();
         String value = (String) params.get(key);
-        transformer.setParameter(key,value);
+        transformer.setParameter(key, value);
       }
-      
+
     }
   }
 
@@ -114,10 +155,9 @@
    */
   public ByteArrayOutputStream createEmptyXmlOutput() throws XMLStreamException {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
-    XMLStreamWriter writer = stax.getStreamWriter(out);
-    writer.writeStartDocument("UTF-8", "1.0");
-    writer.writeStartElement("foo");
-    writer.writeEndDocument();
+    PrintWriter writer = new PrintWriter (out);
+    String doc ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<foo/>";
+    writer.write(doc);
     writer.flush();
     writer.close();
     return out;
@@ -133,10 +173,9 @@
    */
   public InputStream createEmptyXml() throws XMLStreamException {
     ByteArrayOutputStream out = createEmptyXmlOutput();
-    return (out !=null)?StreamHelper.switchStream(out):null;
+    return (out != null) ? StreamHelper.switchStream(out) : null;
   }
 
-
   /**
    * This method sets the xslSource, name, description and usage information of
    * the contract.
@@ -147,170 +186,77 @@
    * @param stream
    * @param contract
    * @throws XMLStreamException
-   * @throws ContractException 
+   * @throws ContractException
    */
   public void setTemplate(InputStream stream, XSLContract contract)
       throws XMLStreamException, ContractException {
-    XMLStreamReader reader = stax.getNSReader(stream);
-    boolean process = true;
-    while (process) {
-      int event = reader.next();
-      switch (event) {
-
-      case XMLStreamConstants.END_DOCUMENT:
-        process = false;
-        break;
-
-      case XMLStreamConstants.START_ELEMENT:
-        String localName = reader.getLocalName();
-        if (localName.equals(Captions.CONTRACT_ELEMENT)) {
-          contract.setName(processContract(reader));
-        }
-        if (localName.equals(Captions.DESCRIPTION_ELEMENT)) {
-          contract.setDescription(processDescription(reader));
-        }
-        if (localName.equals(Captions.USAGE_ELEMENT)) {
-          contract.setUsage(processUsage(reader));
-        }
-
-        if (localName.equals(Captions.TEMPLATE_ELEMENT)) {
-          contract.setXslSource(processTemplate(reader));
-        }
-
-      default:
-        break;
-      }
-    }
-  }
 
-  private Source processTemplate(XMLStreamReader reader) throws ContractException{
-    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    // FIXME: Make encoding configurable
+    ContractHandler handler = new ContractHandler("UTF-8");
     try {
-      XMLEventWriter writer = stax.getWriter(out);
-      // Making sure we always have all ns 
-      // A wee bit brute force but it works
-      XMLEventAllocator allocator = stax.getNSEventAllocator();
-      String role = "";
-      for (int i = 0; i < reader.getAttributeCount(); i++) {
-        // Get attribute name
-        String localName = reader.getAttributeLocalName(i);
-        if (localName.equals(Captions.TEMPLATE_FORMAT_ATT)) {
-          // Return value
-          role = reader.getAttributeValue(i);
-        }
-      }
-      boolean process = true;
-      if (role.equals("xsl")) {
-        while (process) {
-          int event = reader.next();
-          switch (event) {
-
-          case XMLStreamConstants.END_ELEMENT:
-            if (reader.getNamespaceURI() != null) {
-              if (reader.getNamespaceURI().equals(Captions.NS)
-                  && reader.getLocalName().equals(Captions.TEMPLATE_ELEMENT)) {
-                process = false;
-              } else {
-                allocator.allocate(reader,writer);
-              }
-            } else {
-              allocator.allocate(reader,writer);
-            }
-            break;
-
-          default:
-            allocator.allocate(reader,writer);
-            break;
-          }
-        }
-      }
-      writer.flush();
-      log.debug(out.toString());
-    } catch (XMLStreamException e) {
-      throw new ContractException("Fatal error in contract.\n"+e);
-    }
-    Source source = new StreamSource(StreamHelper.switchStream(out));
-    return source;
-  }
-
-  private String processUsage(XMLStreamReader reader) throws XMLStreamException {
-    boolean process = true;
-    String usage = "";
-    while (process) {
-      int event = reader.next();
-      switch (event) {
-
-      case XMLStreamConstants.CHARACTERS:
-        if (reader.getText().replace(" ", "").length() > 1) {
-          usage = reader.getText().trim();
-        }
-        break;
-
-      case XMLStreamConstants.END_ELEMENT:
-        if (reader.getLocalName().equals(Captions.USAGE_ELEMENT)) {
-          process = false;
-        }
-        break;
-
-      default:
-        break;
-      }
-    }
-    return usage;
-  }
-
-  private String processDescription(XMLStreamReader reader)
-      throws XMLStreamException {
-    boolean process = true;
-    String description = "";
-    while (process) {
-      int event = reader.next();
-      switch (event) {
-
-      case XMLStreamConstants.CHARACTERS:
-        if (reader.getText().replace(" ", "").length() > 1) {
-          description = reader.getText().trim();
-        }
-        break;
-
-      case XMLStreamConstants.END_ELEMENT:
-        if (reader.getLocalName().equals(Captions.DESCRIPTION_ELEMENT)) {
-          process = false;
-        }
-        break;
-
-      default:
-        break;
-      }
+      /* DEBUG_CODE: 
+       * The following is useful to see what is going on
+       * 
+       * It will output the contract descriptor as is to 
+       * the system out.
+       */
+      /*
+       * byte[] debug  = IOUtils.toByteArray(stream);
+       * System.out.println(new String(debug));
+       * parser.parse(new ByteArrayInputStream(debug), handler);
+       */
+      // Process the stream by parsing it with the contractHandler
+      parser.parse(stream, handler);
+    } catch (Exception e) {
+      throw new ContractException(e);
     }
-
-    return description;
+    // Setting the necessary attributes of the contract 
+    // xsl
+    contract.setXslSource(new StreamSource(new ByteArrayInputStream(handler
+        .getBytes())));
+    /* DEBUG_CODE: 
+     * The following is useful to see what is going on
+     * 
+     * It will output the xsl stylesheet of the contract descriptor
+     * to the system out.
+     */
+   /* System.out.println(new String(handler
+        .getBytes()));*/
+    // description - what does the contract?
+    contract.setDescription(handler.getDescription());
+    // name - how is the contract called?
+    name = handler.getName();
+    contract.setName(name);
+    // usage - how can the contract be used?
+    contract.setUsage(handler.getUsage());
   }
 
-  private String processContract(XMLStreamReader reader) {
-    String contractName = "";
-    for (int i = 0; i < reader.getAttributeCount(); i++) {
-      // Get attribute name
-      String localName = reader.getAttributeLocalName(i);
-      if (localName.equals(Captions.CONTRACT_NAME_ATT)) {
-        // Return value
-        contractName = reader.getAttributeValue(i);
-        return contractName;
-      }
-    }
-    return contractName;
-  }
+  
 
-  public void transform(InputStream dataStream, Result streamResult) throws ContractException
{
+  /**
+   * Is wrapping {@link javax.xml.transform.Transformer.transform(Source xmlSource, Result
outputTarget)}
+   * to enhancing the exceptions that may have been thrown.
+   * @param dataStream the input stream that we want to transform
+   * @param streamResult the result object where we want to store the outcome of the 
+   * transformation. 
+   * @throws ContractException enhanced error messages for sax and FAQ of the most 
+   * common problems and solutions 
+   */
+  public void transform(InputStream dataStream, Result streamResult)
+      throws ContractException {
     Source dataSource = new StreamSource(dataStream);
     try {
       transformer.transform(dataSource, streamResult);
     } catch (Exception e) {
-      String message ="The xsl transformation has thrown an exception. Please see some FAQ:"+"\n"+e+"\n\nproblem->solution:\n"
+
-      		"- org.apache.xpath.XPathException: Can not convert #STRING to a NodeList!\n" +
-      		"-> Try to activate \"allowXml\" and/or \"shrink\". If this is not working try
the contract " +
-      		"xsl standalone and make sure it is not a xsl specific problem.";
-    throw new ContractException(message);
+      String message = "The xsl transformation has thrown an exception. for "
+            + "the contract \""+name+"\".\nPlease see some FAQ:"
+          + "\n"
+          + e
+          + "\n\nproblem->solution:\n"
+          + "- org.apache.xpath.XPathException: Can not convert #STRING to a NodeList!\n"
+          + "-> Try to activate \"allowXml\" and/or \"shrink\". If this is not working
try the contract "
+          + "xsl standalone and make sure it is not a xsl specific problem.";
+      throw new ContractException(message);
     }
   }
 }



Mime
View raw message