Author: thorsten
Date: Fri Sep 19 03:17:25 2008
New Revision: 697033

URL: http://svn.apache.org/viewvc?rev=697033&view=rev
Log:
Implementation of hook processing. 

There is a small downsides in the current implementation: the xpath injection 
are NOT working well when the injection point is within the main stream of the 
events. 

It is possible to inject e.g. to /html/head but injecting to /html/body/... 
will not inject the new events in the principal stream to the location that one 
w
ould await. The main reason is that the generation of the result document is 
now as well based on StAX and not any more in DOM.

However to have the same behavior as we have currently in the 
DispatcherTransformer I do not see any other possibility then using DOM again.

Like with the xml properties I will make the usage configurable since I reckon 
in 90% of all cases the StAX based calculation is used. For the rest I am stil
l investigating but it seems that DOM is the only possibility because every 
other possibility that me occur is imitating DOM.


Modified:
    
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/config/DispatcherBean.java
    
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/impl/XMLStructurer.java
    
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/TestStructurer.java
    
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.contract.xml
    
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.structurer.xml

Modified: 
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/config/DispatcherBean.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/config/DispatcherBean.java?rev=697033&r1=697032&r2=697033&view=diff
==============================================================================
--- 
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/config/DispatcherBean.java
 (original)
+++ 
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/config/DispatcherBean.java
 Fri Sep 19 03:17:25 2008
@@ -28,6 +28,7 @@
 public class DispatcherBean {
   
   private boolean allowXmlProperties = false;
+  private boolean domEnabled = false;
   private Resolver resolver = null;
 
   private String contractUriPrefix = "";
@@ -65,4 +66,12 @@
     this.contractUriSufix = contractUriSufix;
   }
 
+  public boolean isDomEnabled() {
+    return domEnabled;
+  }
+  
+  public void setDomEnabled(boolean domEnabled) {
+    this.domEnabled = domEnabled;
+  }
+
 }

Modified: 
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/impl/XMLStructurer.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/impl/XMLStructurer.java?rev=697033&r1=697032&r2=697033&view=diff
==============================================================================
--- 
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/impl/XMLStructurer.java
 (original)
+++ 
forrest/trunk/whiteboard/dispatcher/java/org/apache/forrest/dispatcher/impl/XMLStructurer.java
 Fri Sep 19 03:17:25 2008
@@ -55,17 +55,20 @@
 
   private static final Object CONTRACT_RESULT_XPATH = "xpath";
 
-  private String currentPath = "";
-  
-  private Resolver resolver = null;
+  private final boolean dom;
 
-  private boolean allowXmlProperties = false;
+  private final Resolver resolver;
 
-  private LinkedHashMap<String, LinkedHashSet<XMLEvent>> resultTree = new 
LinkedHashMap<String, LinkedHashSet<XMLEvent>>();
+  private final boolean allowXmlProperties;
+  
+  private final ContractFactory contractRep;
 
-  private ContractFactory contractRep =null;
+  private LinkedHashMap<String, LinkedHashSet<XMLEvent>> resultTree = new 
LinkedHashMap<String, LinkedHashSet<XMLEvent>>();
   
+  private String currentPath = "";
+
   public XMLStructurer(DispatcherBean config) {
+    this.dom= config.isDomEnabled();
     this.contractRep = new ContractFactory(config);
     this.resolver = config.getResolver();
     this.allowXmlProperties = config.isAllowXmlProperties();
@@ -139,43 +142,22 @@
     boolean process = true;
     String elementName = null;
     ByteArrayOutputStream out = new ByteArrayOutputStream();
-    XMLEventWriter writer = getWriter(out);
     while (process) {
       int event = reader.next();
       switch (event) {
       case XMLStreamConstants.END_ELEMENT:
         elementName = reader.getLocalName();
         if (elementName.equals(STRUCTURE_ELEMENT)) {
-          writer.add(getEventFactory().createStartDocument("UTF-8", "1.0"));
-          Iterator<String> iterator = resultTree.keySet().iterator();
-          String[] paths = resultTree.keySet().toArray(new String[1]);
-          String rootPath = CommonString.common(paths);
-          String[] tokenizer = rootPath.split("/");
-          openPaths(writer, tokenizer);
-          while (iterator.hasNext()) {
-            String element = iterator.next();
-            final String replaceFirst = element.replaceFirst(rootPath, "");
-            final String[] split = replaceFirst.split("/");
-            if (split.length > 1) {
-              openPaths(writer, split);
-              injectResult(writer, element);
-              closingPaths(writer, split);
-            } else {
-              StartElement start = getEventFactory().createStartElement("", "",
-                  replaceFirst);
-              writer.add((XMLEvent) start);
-
-              injectResult(writer, element);
-              EndElement end = getEventFactory().createEndElement("", "",
-                  replaceFirst);
-              writer.add((XMLEvent) end);
-            }
-
+          if(dom){
+            // TODO implement me.
+          }else{
+            XMLEventWriter writer = getWriter(out);
+            createResultStax(writer);
           }
-          closingPaths(writer, tokenizer);
-          writer.add(getEventFactory().createEndDocument());
           resultTree.clear();
           process = false;
+        }else if (elementName.equals(HOOK_ELEMENT)){
+          processHook(reader, false);
         }
         break;
 
@@ -186,6 +168,7 @@
           processContract(reader);
         } else if (elementName.equals(HOOK_ELEMENT)) {
           log.debug("HOOKS " + elementName);
+          processHook(reader, true);
           log.info("HOOKS transformation NOT YET IMPLEMENTED");
         }
         break;
@@ -199,6 +182,52 @@
     return (out != null) ? new BufferedInputStream(new ByteArrayInputStream(out
         .toByteArray())) : null;
   }
+  
+  /**
+   * Create the outcome of the hooks and contracts.
+   * Here we need to find the injectionPoints that 
+   * can be defined in the different contracts.
+   * 
+   * This injectionPoints can be within or extending other. 
+   */
+
+  private void createResultStax(XMLEventWriter writer)
+      throws XMLStreamException {
+    // We start with creating a new result document
+    writer.add(getEventFactory().createStartDocument("UTF-8", "1.0"));
+    // get a iterator about the injectionPoints we use
+    Iterator<String> iterator = resultTree.keySet().iterator();
+    // create an path array 
+    String[] paths = resultTree.keySet().toArray(new String[1]);
+    // determine the common root path for all paths
+    String rootPath = CommonString.common(paths);
+    // Prepare the creation of the root path  
+    String[] tokenizer = rootPath.split("/");
+    // create the events related to the root path
+    openPaths(writer, tokenizer);
+    while (iterator.hasNext()) {
+      String element = iterator.next();
+      final String replaceFirst = element.replaceFirst(rootPath, "");
+      final String[] split = replaceFirst.split("/");
+      if (split.length > 1) {
+        openPaths(writer, split);
+        injectResult(writer, element);
+        closingPaths(writer, split);
+      } else {
+        StartElement start = getEventFactory().createStartElement("", "",
+            replaceFirst);
+        writer.add((XMLEvent) start);
+
+        injectResult(writer, element);
+        EndElement end = getEventFactory().createEndElement("", "",
+            replaceFirst);
+        writer.add((XMLEvent) end);
+      }
+
+    }
+    closingPaths(writer, tokenizer);
+    writer.add(getEventFactory().createEndDocument());
+  }
 
   private void processContract(XMLStreamReader reader)
       throws XMLStreamException, DispatcherException, IOException {
@@ -277,10 +306,11 @@
           if (xpath.equals("")) {
             // iterate through the children and add them
             // to the pathElement
-            if (resultTree.containsKey(currentPath))
+            if (resultTree.containsKey(currentPath)){
               pathElement = resultTree.get(currentPath);
-            else
+            }else{
               pathElement = new LinkedHashSet<XMLEvent>();
+            }
             injectionPoint = currentPath;
             inject(pathElement, contractResultReader, injectionPoint);
             // as soon as you find the end element add
@@ -306,6 +336,45 @@
       }
     }
   }
+  
+  private void processHook(XMLStreamReader reader, boolean start) throws 
XMLStreamException {
+    
+    /*log.debug("currentPath: "+currentPath);
+    if(start){
+      String xpath= calculateXpathFromAtrributes(reader);
+      //currentPath+="/"+
+      log.debug(currentPath+"/"+HOOK_ELEMENT.toUpperCase()+xpath);
+      currentPath+="/"+HOOK_ELEMENT;
+    }*/
+    LinkedHashSet<XMLEvent> pathElement;
+    if (resultTree.containsKey(currentPath)){
+      pathElement = resultTree.get(currentPath);
+    }else{
+      pathElement = new LinkedHashSet<XMLEvent>();
+    }
+    XMLEventAllocator allocator = getEventAllocator();
+    XMLEvent currentEvent = allocator.allocate(reader);
+    pathElement.add(currentEvent);
+    resultTree.put(currentPath, pathElement);
+    /*if(!start){
+      
currentPath=currentPath.substring(0,currentPath.lastIndexOf(("/"+HOOK_ELEMENT)));
+    }
+    log.debug("currentPath (after): "+currentPath);*/
+  }
+
+  private String calculateXpathFromAtrributes(XMLStreamReader reader) {
+    String xpath="";
+    for (int i = 0; i < reader.getAttributeCount(); i++) {
+      // Get attribute name
+      String key = reader.getAttributeLocalName(i);
+      String  value = reader.getAttributeValue(i);
+      xpath="@"+key+":"+value;
+    }
+    if(!xpath.equals("")){
+      xpath="["+xpath+"]";
+    }
+    return xpath;
+  }
 
   private void inject(LinkedHashSet<XMLEvent> pathElement,
       XMLStreamReader parser, String injectionPoint) throws XMLStreamException 
{
@@ -390,10 +459,10 @@
 
   private void openPaths(XMLEventWriter writer, String[] tokenizer)
       throws XMLStreamException {
-    for (int i = 0; i < tokenizer.length; i++) {
-      if (!tokenizer[i].equals("")) {
+    for (String string : tokenizer) {
+      if (!string.equals("")) {
         StartElement value = getEventFactory().createStartElement("", "",
-            tokenizer[i]);
+            string);
         writer.add((XMLEvent) value);
       }
     }

Modified: 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/TestStructurer.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/TestStructurer.java?rev=697033&r1=697032&r2=697033&view=diff
==============================================================================
--- 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/TestStructurer.java
 (original)
+++ 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/TestStructurer.java
 Fri Sep 19 03:17:25 2008
@@ -16,7 +16,7 @@
     String format = "html";
     Structurer structurer = prepareStructurer(false);
     structurer.execute(getStream(),format);
-  }
+  }/*
   public void testStructurerWithXmlProperties() throws DispatcherException{
     String format = "html";
     Structurer structurer = prepareStructurer(true);
@@ -26,7 +26,7 @@
     String format = "xml";
     Structurer structurer = prepareStructurer(false);
     structurer.execute(getStream(), format);
-  }
+  }*/
   private Structurer prepareStructurer(boolean allowXml) {
     DispatcherBean config = new DispatcherBean();
     config.setAllowXmlProperties(allowXml);

Modified: 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.contract.xml
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.contract.xml?rev=697033&r1=697032&r2=697033&view=diff
==============================================================================
--- 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.contract.xml
 (original)
+++ 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.contract.xml
 Fri Sep 19 03:17:25 2008
@@ -42,6 +42,9 @@
               content=" Content going to a fixed location defined by the 
contract (here: /html/head)."
               name="Description" />
           </forrest:part>
+          <forrest:part xpath="/html/body/hook/hook">
+            <p>master-xxx</p>
+          </forrest:part>
         </forrest:content>
       </xsl:template>
     </xsl:stylesheet>

Modified: 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.structurer.xml
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.structurer.xml?rev=697033&r1=697032&r2=697033&view=diff
==============================================================================
--- 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.structurer.xml
 (original)
+++ 
forrest/trunk/whiteboard/dispatcher/testing/org/apache/forrest/dispatcher/master.structurer.xml
 Fri Sep 19 03:17:25 2008
@@ -15,18 +15,25 @@
   -->
 <structurer xmlns="http://apache.org/forrest/templates/2.0";>
   <structure type="html" hooksXpath="/html/body">
-    <contract name="master">
-      <property name="test-inline-xml">
-        <css url="common.css" />
+    <hook id="example">
+      <contract name="master">
+        <property name="test-inline-xml">
+          <css url="common.css" />
 <!--<nupp/>-->
-      </property>
-      <property name="test-inline" value="test" />
-    </contract>
+        </property>
+        <property name="test-inline" value="position:hook/contract" />
+      </contract>
+      <hook id="level2">
+        <contract name="master">
+          <property name="test-inline" value="position:hook/hook/contract" />
+        </contract>
+      </hook>
+    </hook>
     <contract name="m2" dataURI="">
       <property name="test-inline" value="xxx" />
     </contract>
   </structure>
   <structure type="xml" hooksXpath="/">
-    <contract name="convertor" 
dataURI="/org/apache/forrest/dispatcher/common.fv"/>
+    <contract name="convertor" 
dataURI="/org/apache/forrest/dispatcher/common.fv" />
   </structure>
 </structurer>
\ No newline at end of file