You are viewing a plain text version of this content. The canonical link for it is here.
Posted to svn@forrest.apache.org by th...@apache.org on 2005/11/30 12:15:16 UTC

svn commit: r349923 [1/2] - in /forrest/trunk: main/template-sites/v2/src/documentation/content/xdocs/ main/template-sites/v2/src/documentation/resources/themes/common/html/ whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/...

Author: thorsten
Date: Wed Nov 30 03:14:46 2005
New Revision: 349923

URL: http://svn.apache.org/viewcvs?rev=349923&view=rev
Log:
First preview of the dispatcher transformer. The transformer is not yet finished, this commit is more a basis for discussion and a personal online 
backup then a finished first implementation!!!

See changes in the output.xmap to see how to define the transformer. If you test in v2 then request http://localhost:8888/test.dispatcher to see code 
in action. 

I added my testing code as well to better test the transformer, consider this code as foo-code-> no functionality just testing.


Added:
    forrest/trunk/main/template-sites/v2/src/documentation/content/xdocs/index-foo.fv
    forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing-foo.ft
    forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing.ft
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java   (with props)
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherException.java   (with props)
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherHelper.java   (with props)
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java   (with props)
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/util/
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/util/SourceUtil.java   (with props)
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/DocumentHelper.java   (with props)
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/NamespaceHelper.java   (with props)
Modified:
    forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.output.themer/output.xmap

Added: forrest/trunk/main/template-sites/v2/src/documentation/content/xdocs/index-foo.fv
URL: http://svn.apache.org/viewcvs/forrest/trunk/main/template-sites/v2/src/documentation/content/xdocs/index-foo.fv?rev=349923&view=auto
==============================================================================
--- forrest/trunk/main/template-sites/v2/src/documentation/content/xdocs/index-foo.fv (added)
+++ forrest/trunk/main/template-sites/v2/src/documentation/content/xdocs/index-foo.fv Wed Nov 30 03:14:46 2005
@@ -0,0 +1,32 @@
+<forrest:views xmlns:forrest="http://apache.org/forrest/templates/1.0" 
+  xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
+  <forrest:view type="xml">
+    <forrest:hook name="test">
+      <forrest:contract name="nav-main-testing" 
+        dataURI="cocoon://index.navigation.xml">
+        <forrest:property name="nav-main-testing-test1" >x</forrest:property>
+        <forrest:property name="nav-main-testing-test2" >
+          <foo/>
+        </forrest:property>
+        <forrest:property name="nav-main-testing-test3" >xxx</forrest:property>
+      </forrest:contract>
+    </forrest:hook>
+  </forrest:view>
+  <forrest:view type="html" hooksXpath="/html/body">
+    <forrest:hook name="test">
+      <forrest:hook name="anotherXz">
+        <forrest:contract name="nav-main-testing-foo" />
+      </forrest:hook>
+      <forrest:hook name="test2">
+        <forrest:contract name="nav-main-testing" 
+          dataURI="cocoon://index.navigation.xml">
+          <forrest:property name="nav-main-testing-test1" >x</forrest:property>
+          <forrest:property name="nav-main-testing-test2" >
+            <foo/>
+          </forrest:property>
+        </forrest:contract>
+      </forrest:hook>
+    </forrest:hook>
+    <forrest:hook name="anotherX"/>
+  </forrest:view>
+</forrest:views>
\ No newline at end of file

Added: forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing-foo.ft
URL: http://svn.apache.org/viewcvs/forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing-foo.ft?rev=349923&view=auto
==============================================================================
--- forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing-foo.ft (added)
+++ forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing-foo.ft Wed Nov 30 03:14:46 2005
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2002-2005 The Apache Software Foundation or its licensors,
+  as applicable.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<forrest:contract name="nav-main-testing-foo" type="nugget"
+  xmlns:forrest="http://apache.org/forrest/templates/1.0">
+  <description>
+    nav-main will output the main or primary navigation AKA tabs.
+  </description>
+  <usage><![CDATA[<forrest:contract name="nav-main-testing-foo" nugget="cocoon://#{$cocoon/parameters/getRequest}.navigation.xml"/>]]>
+    </usage>
+  <forrest:template
+  xmlns:forrest="http://apache.org/forrest/templates/1.0"
+  format="html" name="nav-main-testing-foo" inputFormat="xsl" >
+    <xsl:stylesheet version="1.1" 
+      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+      <xsl:template match="/" >
+        <forrest:content>
+          <forrest:part> nav-main-testing-foo testing - no @xpath</forrest:part>
+        </forrest:content>
+      </xsl:template>
+    </xsl:stylesheet>
+	</forrest:template>
+</forrest:contract>
\ No newline at end of file

Added: forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing.ft
URL: http://svn.apache.org/viewcvs/forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing.ft?rev=349923&view=auto
==============================================================================
--- forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing.ft (added)
+++ forrest/trunk/main/template-sites/v2/src/documentation/resources/themes/common/html/nav-main-testing.ft Wed Nov 30 03:14:46 2005
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2002-2005 The Apache Software Foundation or its licensors,
+  as applicable.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<forrest:contract name="nav-main-testing" type="nugget"
+  xmlns:forrest="http://apache.org/forrest/templates/1.0">
+  <description>
+    nav-main will output the main or primary navigation AKA tabs.
+  </description>
+  <usage><![CDATA[<forrest:contract name="nav-main-testing" nugget="cocoon://#{$cocoon/parameters/getRequest}.navigation.xml"/>]]>
+    </usage>
+  <forrest:template
+  xmlns:forrest="http://apache.org/forrest/templates/1.0"
+  format="html" name="nav-main-testing" inputFormat="xsl" >
+
+    <xsl:stylesheet version="1.1" 
+      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+      <xsl:param name="nav-main-testing" select="/"/>
+      <xsl:param name="nav-main-testing-test1" select="'test'"/>
+      <xsl:template match="/" >
+        <forrest:content>
+          <forrest:part>
+             value-of select="$nav-main-testing-test1": <xsl:value-of select="$nav-main-testing-test1"/>
+            <div id="tabs"> <xsl:comment>+ |start Tabs new +</xsl:comment> 
+             <xsl:copy-of 
+              select="$nav-main-testing/navigation/tab/ul[@id='nav-main']"/> 
+              <xsl:comment>+ |end Tabs +</xsl:comment> </div>
+          </forrest:part>
+          <forrest:part xpath="/html/head">
+            <forrest:part> nav-main-testing-foo testing -  xpath="/html/head"</forrest:part>
+          </forrest:part>
+        </forrest:content>
+      </xsl:template>
+    </xsl:stylesheet>
+	</forrest:template>
+</forrest:contract>
\ No newline at end of file

Added: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java
URL: http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java?rev=349923&view=auto
==============================================================================
--- forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java (added)
+++ forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java Wed Nov 30 03:14:46 2005
@@ -0,0 +1,437 @@
+package org.apache.forrest.dispatcher;
+
+import java.beans.Beans;
+import java.util.HashMap;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.lenya.xml.NamespaceHelper;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author thorsten
+ * 
+ */
+public class ContractBean extends Beans {
+
+    /**
+     * The resolver prefix
+     */
+    public static final String CONTRACT_RESOLVE_PREFIX = "cocoon://resolve.contract";
+
+    /**
+     * <code>forrest:contract</code> element is used to include extra content
+     * and/or functionality.
+     * 
+     * <p>
+     * extra functionality requested from a uri via CONTRACT_NUGGET_ATTRIBUTE
+     * attribute - example:
+     * </p>
+     * 
+     * <pre>
+     *                       &lt;forrest:contract name=&quot;nav-section&quot; dataURI=&quot;cocoon://index.navigation.xml&quot;/&gt;
+     * </pre>
+     */
+    public static final String CONTRACT_ELEMENT = "contract";
+
+    /**
+     * Each contract can contact business services to get the data model. The
+     * attribute "CONTRACT_NUGGET_ATTRIBUTE" contains the uri to contact for
+     * business data
+     */
+    public static final String CONTRACT_NUGGET_ATTRIBUTE = "dataURI";
+
+    /**
+     * Each contract must have an unique identifier. The attribute "CONTRACT_ID_ATTRIBUTE"
+     * contains this id
+     */
+    public static final String CONTRACT_ID_ATTRIBUTE = "name";
+    
+    /**
+     * Each contract implementation needs to define the input format for the transformation. 
+     * ATM we only support xsl. The attribute "CONTRACT_IMPL_INPUT_FORMAT_ATTRIBUTE"
+     * defines the input format for transformation
+     */
+    public static final String CONTRACT_IMPL_INPUT_FORMAT_ATTRIBUTE = "inputFormat";
+
+    /**
+     * Each contract implementation needs to define the input format for the transformation. 
+     * ATM we only support xsl. The attribute "CONTRACT_IMPL_INPUT_FORMAT_ATTRIBUTE"
+     * defines the input format for transformation
+     */
+    public static final String CONTRACT_IMPL_ROOT_ELEMENT = "forrest:template";
+    
+    private static final String PROPERTY_ID_ATTRIBUTE = "name";
+
+    private HashMap contract;
+
+    private Element structurerContract;
+
+    private Element[] propertyList;
+
+    private Document contractImpl;
+
+    private Element contractDescription;
+
+    private Element contractUsage;
+
+    private Document contractRawData;
+
+    private Transformer contractTransformer;
+
+    private DOMResult contractResultData;
+
+    private boolean isNugget = false;
+
+    private boolean hasProperties = false;
+
+    private String contractName;
+
+    private String nuggetUri;
+
+    protected NamespaceHelper namespaceHelper;
+
+    protected DispatcherHelper dispatcherHelper;
+
+    protected ServiceManager manager;
+
+    /**
+     * @param element
+     * @param namespaceHelper
+     * @deprecated
+     */
+    public ContractBean(Element element, NamespaceHelper namespaceHelper) {
+        this.contract = new HashMap();
+        this.namespaceHelper = namespaceHelper;
+        this.loadStructurer(element);
+    }
+
+    /**
+     * The ContractBean contains all fields to work with contracts. It is a
+     * helper bean.
+     * 
+     * Helpers (forrest:contracts) mainly adapt and transform the presentation
+     * model (pm), but also help with any limited business processing that is
+     * initiated from the structurer by forrest:properties by passing this
+     * information to the transfomer.
+     * 
+     * @param manager
+     * @throws ParserConfigurationException
+     */
+    public ContractBean(ServiceManager manager)
+            throws ParserConfigurationException {
+        this.manager = manager;
+        this.contract = new HashMap();
+        dispatcherHelper = new DispatcherHelper(manager);
+    }
+
+    /**
+     * The ContractBean contains all fields to work with contracts. It is a
+     * helper bean.
+     * 
+     * Helpers (forrest:contracts) mainly adapt and transform the presentation
+     * model (pm), but also help with any limited business processing that is
+     * initiated from the structurer by forrest:properties by passing this
+     * information to the transfomer.
+     * 
+     * @throws ParserConfigurationException
+     */
+    public ContractBean() {}
+
+    /**
+     * @param structurer
+     * @deprecated
+     */
+    private void loadStructurer(Element structurer) {
+        this.setStructurerContract(structurer);
+        this.setNugget(structurer.hasAttribute(CONTRACT_NUGGET_ATTRIBUTE));
+        this.setHasProperties(structurer.hasChildNodes());
+        if (hasProperties) {
+            this.propertyList = namespaceHelper.getChildren(structurer);
+        }
+        this.setContractName(structurer.getAttribute(CONTRACT_ID_ATTRIBUTE));
+        /*
+         * if (this.isNugget) { this.setNuggetUri(structurer
+         * .getAttribute(CONTRACT_NUGGET_ATTRIBUTE)); }
+         */
+    }
+
+    /**
+     * setContractImpl(String contractUri)
+     * 
+     * This method set the actual contract implementation via a URI.
+     * 
+     * Here we set the description and the usage instruction of the contract
+     * implementation. As well we prepare the transformer. The simplest form is
+     * a contract that does not need a pm. It can provide all data through the
+     * transformation. A more dynamic contract would provide properties to the
+     * transformation (contractImpl) to apply limited business logic.
+     * 
+     * @param contractUri
+     * @throws Exception
+     */
+    public void setContractImpl(String contractUri) throws Exception {
+        Document contractImpl = dispatcherHelper.getDocument(contractUri);
+        this.contractImpl = contractImpl;
+        contractImplHelper(contractImpl);
+    }
+
+    /**
+     * setContractImpl(String contractUri)
+     * 
+     * This method set the actual contract implementation via a URI.
+     * 
+     * Here we set the description and the usage instruction of the contract
+     * implementation. As well we prepare the transformer. The simplest form is
+     * a contract that does not need a pm. It can provide all data through the
+     * transformation. A more dynamic contract would provide properties to the
+     * transformation (contractImpl) to apply limited business logic.
+     * 
+     * @param contractUri
+     * @throws Exception
+     */
+    public void setContractImpl(Document contractImpl) throws Exception {
+        this.contractImpl = contractImpl;
+        contractImplHelper(contractImpl);
+    }
+
+    /**
+     * @param contractImpl
+     * @throws Exception
+     * @throws TransformerFactoryConfigurationError
+     * @throws TransformerConfigurationException
+     * @throws IllegalArgumentException
+     */
+    private void contractImplHelper(Document contractImpl) throws Exception,
+            TransformerFactoryConfigurationError,
+            TransformerConfigurationException, IllegalArgumentException {
+        NodeList template = contractImpl
+                .getElementsByTagName(CONTRACT_IMPL_ROOT_ELEMENT);
+        if (template.getLength() == 1) {
+            Element templateElement = (Element) template.item(0);
+            String format = templateElement.getAttribute(CONTRACT_IMPL_INPUT_FORMAT_ATTRIBUTE);
+            if ("".equals(format) | format == null) {
+                throw new DispatcherException(DispatcherException.ERROR_500 + "\n"
+                        + "component: ContractBean" + "\n"
+                        + "message: inputFormat cannot be null");
+            } else if ("xsl".equals(format)) {
+                NodeList list_transformer = contractImpl
+                        .getElementsByTagName("xsl:stylesheet");
+                if (list_transformer.getLength() == 1) {
+                    Element node = (Element) list_transformer.item(0);
+                    TransformerFactory tFactory = TransformerFactory
+                            .newInstance();
+                    DOMSource stylesource = new DOMSource(node);
+                    Transformer transformer = tFactory
+                            .newTransformer(stylesource);
+                    if (transformer == null)
+                        throw new DispatcherException(
+                                DispatcherException.ERROR_500
+                                        + "\n"
+                                        + "component: ContractBean"
+                                        + "\n"
+                                        + "message: Could not setup transformer in the contractBean."
+                                        + "\n"
+                                        + "Please check that the contract implementation is wellformed and valid");
+                    /*
+                     * FIXME: Set default properties
+                     */
+                    // transformer.setParameter()
+                    transformer.setOutputProperty(
+                            OutputKeys.OMIT_XML_DECLARATION, "yes");
+                    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+                    transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+                    this.contractTransformer = transformer;
+                }
+            } else {
+                throw new DispatcherException( DispatcherException.ERROR_404+ "\n"
+                        + "component: ContractBean" + "\n"
+                        + "message: inputFormat=\""+format+"\" not implemented");
+            }
+        }
+        NodeList description = contractImpl.getElementsByTagName("description");
+        if (description.getLength() == 1) {
+            Element node = (Element) description.item(0);
+            this.contractDescription = node;
+        }
+        NodeList usage = contractImpl.getElementsByTagName("usage");
+        if (usage.getLength() == 1) {
+            Element node = (Element) usage.item(0);
+            this.contractUsage = node;
+        }
+    }
+
+    public HashMap getContract() {
+        return contract;
+    }
+
+    public void put(Object key, Object element) {
+        this.contract.put(key, element);
+    }
+
+    public String getContractName() {
+        return contractName;
+    }
+
+    public void setContractName(String contractName) {
+        this.contractName = contractName;
+    }
+
+    public boolean isHasProperties() {
+        return hasProperties;
+    }
+
+    public void setHasProperties(boolean hasProperties) {
+        this.hasProperties = hasProperties;
+    }
+
+    public boolean isNugget() {
+        return isNugget;
+    }
+
+    public void setNugget(boolean isNugget) {
+        this.isNugget = isNugget;
+    }
+
+    public String getNuggetUri() {
+        return nuggetUri;
+    }
+
+    /**
+     * The presentation model (contractRawData) has to be requested by the
+     * contract if it needs it. This is be done by setting the
+     * CONTRACT_NUGGET_ATTRIBUTE attribute in the structurer which then use this
+     * method to set the contractRawData.
+     * <p>
+     * Extra functionality requested from a uri via CONTRACT_NUGGET_ATTRIBUTE
+     * attribute - example:
+     * </p>
+     * 
+     * <pre>
+     *                      &lt;forrest:contract name=&quot;nav-section&quot; dataURI=&quot;cocoon://index.navigation.xml&quot;/&gt;
+     * </pre>
+     * 
+     * @param nuggetUri
+     * @throws Exception
+     */
+    public void setNuggetUri(String nuggetUri) throws Exception {
+        this.nuggetUri = nuggetUri;
+        Document rawData = dispatcherHelper.getDocument(nuggetUri);
+        this.contractRawData = rawData;
+    }
+
+    public Node getContractRawData() {
+        return contractRawData;
+    }
+
+    /**
+     * This method invokes the transformation of the this.contractRawData with
+     * the this.contractTransformer (make sure you set them before). The result
+     * is set to this.contractResultData.
+     * 
+     * @throws TransformerException
+     */
+    public void setContractResultData() throws TransformerException {
+        if (this.getContractRawData() == null
+                || this.contractTransformer == null) {
+            throw new TransformerException(
+                    "You need to invoke first the transfomer and the rawData.");
+        } else {
+            DOMSource source = new DOMSource(contractRawData);
+            DOMResult result = new DOMResult();
+            this.contractTransformer.transform(source, result);
+            this.setContractResultData(result);
+        }
+    }
+
+    public void setContractRawData(Document contractRawData) {
+        this.contractRawData = contractRawData;
+    }
+
+    public Transformer getContractTransformer() {
+        return contractTransformer;
+    }
+
+    public void setContractTransformer(Transformer contractTransformer) {
+        this.contractTransformer = contractTransformer;
+    }
+
+    public Element getStructurerContract() {
+        return structurerContract;
+    }
+
+    public void setStructurerContract(Element structurerContract) {
+        this.structurerContract = structurerContract;
+    }
+
+    public Document getContractImpl() {
+        return contractImpl;
+    }
+
+    public Element getContractDescription() {
+        return contractDescription;
+    }
+
+    public void setContractDescription(Element contractDescription) {
+        this.contractDescription = contractDescription;
+    }
+
+    public Element getContractUsage() {
+        return contractUsage;
+    }
+
+    public void setContractUsage(Element contractUsage) {
+        this.contractUsage = contractUsage;
+    }
+
+    public Element[] getPropertyList() {
+        return propertyList;
+    }
+
+    public void setPropertyList(Element[] propertyList) {
+        this.propertyList = propertyList;
+    }
+
+    public DOMResult getContractResultData() {
+        return contractResultData;
+    }
+
+    public void setContractResultData(DOMResult contractResultData) {
+        this.contractResultData = contractResultData;
+    }
+
+    public void recycle() {
+        this.contract = null;
+        this.contractDescription = null;
+        this.contractImpl = null;
+        this.contractName = null;
+        this.contractRawData = null;
+        this.contractResultData = null;
+        this.contractTransformer = null;
+        this.contractUsage = null;
+        this.dispatcherHelper = null;
+        this.hasProperties = false;
+        this.isNugget = false;
+        this.namespaceHelper = null;
+        this.nuggetUri = null;
+        this.propertyList = null;
+        this.structurerContract = null;
+    }
+
+    public void initialize() throws ParserConfigurationException {
+        this.contract = new HashMap();
+        dispatcherHelper = new DispatcherHelper(this.manager);
+    }
+}

Propchange: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherException.java
URL: http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherException.java?rev=349923&view=auto
==============================================================================
--- forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherException.java (added)
+++ forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherException.java Wed Nov 30 03:14:46 2005
@@ -0,0 +1,46 @@
+package org.apache.forrest.dispatcher;
+
+/**
+ * Dispatcher Exception
+ */
+public class DispatcherException extends Exception {
+    public static final String ERROR_404 =  "code: 404 - Source not found";
+    public static final String ERROR_500 =  "code: 500 - Internal server error";
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Creates a new DispatcherException.
+     */
+    public DispatcherException() {
+        super();
+    }
+
+    /**
+     * Creates a new DispatcherException.
+     * @param message the exception message
+     */
+    public DispatcherException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a new DispatcherException.
+     * @param message the exception message
+     * @param cause the cause of the exception
+     */
+    public DispatcherException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a new DispatcherException.
+     * @param cause the cause of the exception
+     */
+    public DispatcherException(Throwable cause) {
+        super(cause);
+    }
+
+}

Propchange: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherHelper.java
URL: http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherHelper.java?rev=349923&view=auto
==============================================================================
--- forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherHelper.java (added)
+++ forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherHelper.java Wed Nov 30 03:14:46 2005
@@ -0,0 +1,96 @@
+package org.apache.forrest.dispatcher;
+
+import java.beans.Beans;
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.xml.IncludeXMLConsumer;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.cocoon.xml.dom.DOMBuilder;
+import org.apache.excalibur.source.SourceNotFoundException;
+import org.apache.lenya.xml.NamespaceHelper;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public class DispatcherHelper extends Beans {
+    /**
+     * The namespace for the dispatcher configuration is
+     * http://apache.org/forrest/templates/1.0
+     */
+    static public final String DISPATCHER_NAMESPACE_URI = "http://apache.org/forrest/templates/1.0";
+
+    /**
+     * The namespace prefix for this namespace.
+     */
+    static public final String DISPATCHER_PREFIX = "forrest";
+
+    private NamespaceHelper namespaceHelper;
+
+    private ServiceManager manager;
+
+    /**
+     * Create a DOM representation of this dispatcher.
+     * 
+     * @return A DOM document.
+     * @throws ServiceException
+     *             if a general error occurs.
+     * @throws SourceNotFoundException
+     *             if the dispatcher's source can not be found
+     * @throws ParserConfigurationException
+     *             if an error occurs during XML parsing.
+     * @throws SAXException
+     *             if an error occurs during XML parsing.
+     * @throws IOException
+     *             if an error occurs during source access..
+     */
+    protected Document getDocument(String uri) throws Exception {
+        Document doc = org.apache.forrest.dispatcher.util.SourceUtil.readDOM(uri,
+                this.manager);
+        if (doc != null) {
+            this.namespaceHelper = new NamespaceHelper(
+                    DISPATCHER_NAMESPACE_URI, DISPATCHER_PREFIX, doc);
+        }
+        return namespaceHelper.getDocument();
+    }
+
+    /**
+     * Creates a new document with the param rootName
+     * 
+     * @param rootName
+     * @return
+     * @throws SAXException
+     */
+    public Document createDocument(String rootName) throws SAXException {
+        DOMBuilder builder = new DOMBuilder();
+        builder.startDocument();
+        builder.startElement("", rootName, rootName, XMLUtils.EMPTY_ATTRIBUTES);
+        builder.endElement("", rootName, rootName);
+        builder.endDocument();
+        return builder.getDocument();
+
+    }
+
+    public DispatcherHelper(ServiceManager manager)
+            throws ParserConfigurationException {
+        this.manager = manager;
+        this.namespaceHelper = new NamespaceHelper(DISPATCHER_NAMESPACE_URI,
+                DISPATCHER_PREFIX, "foo");
+    }
+
+    public NamespaceHelper getNamespaceHelper() {
+        return namespaceHelper;
+    }
+
+    public void setNamespaceHelper(NamespaceHelper namespaceHelper) {
+        this.namespaceHelper = namespaceHelper;
+    }
+
+    public void setNamespaceHelper(String uri, String prefix, String localName)
+            throws ParserConfigurationException {
+        this.namespaceHelper = new NamespaceHelper(uri, prefix, localName);
+    }
+
+}

Propchange: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/DispatcherHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java
URL: http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java?rev=349923&view=auto
==============================================================================
--- forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java (added)
+++ forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java Wed Nov 30 03:14:46 2005
@@ -0,0 +1,838 @@
+package org.apache.forrest.dispatcher.transformation;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.caching.CacheableProcessingComponent;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.transformation.AbstractSAXTransformer;
+import org.apache.cocoon.xml.IncludeXMLConsumer;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.cocoon.xml.dom.DOMBuilder;
+import org.apache.cocoon.xml.dom.DOMUtil;
+import org.apache.excalibur.source.SourceValidity;
+import org.apache.excalibur.xml.xpath.XPathProcessor;
+import org.apache.forrest.dispatcher.ContractBean;
+import org.apache.forrest.dispatcher.DispatcherHelper;
+import org.apache.lenya.xml.NamespaceHelper;
+import org.apache.xpath.CachedXPathAPI;
+import org.apache.xpath.XPathAPI;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import org.w3c.dom.DOMImplementation;
+
+public class DispatcherTransformer extends AbstractSAXTransformer implements
+        Disposable, CacheableProcessingComponent {
+
+    /* Node and attribute names */
+    /**
+     * <code>forrest:view</code> element is used to structure contracts and
+     * hooks into format specific container. It allows to configure x different
+     * format for the request.
+     * 
+     * <pre>
+     *                          &lt;&lt;strong&gt;forrest:view&lt;/strong&gt; format=&quot;html&quot;/&gt;
+     * </pre>
+     */
+    public static final String STRUCTURER_ELEMENT = "view";
+
+    /**
+     * <code>forrest:view</code> element is used to structure contracts and
+     * hooks into format specific container. It allows to configure x different
+     * format for the request. The attribute which identify a view format is
+     * <strong>format</strong>.
+     * 
+     * <pre>
+     *                          &lt;forrest:view &lt;strong&gt;format&lt;/strong&gt;=&quot;html&quot;/&gt;
+     * </pre>
+     */
+    public static final String STRUCTURER_FORMAT_ATTRIBUTE = "type";
+
+    public static final String STRUCTURER_HOOK_XPATH_ATTRIBUTE = "hooksXpath";
+
+    protected String requestedFormat;
+
+    private boolean includeNodes = true;
+
+    /**
+     * <code>forrest:hook</code> element is used to structure the elements. It
+     * allows to create skeletons that a designer needs to apply a specific
+     * layout via e.g. css. In html for example
+     * 
+     * <pre>
+     *                          &lt;forrest:hook name=&quot;test&quot;/&gt;
+     * </pre>
+     * 
+     * <p>
+     * will be transformed to
+     * </p>
+     * 
+     * <pre>
+     *                          &lt;div id=&quot;test&quot;/&gt;
+     * </pre>
+     */
+    public static final String DISPATCHER_HOOK_ELEMENT = "hook";
+
+    /**
+     * <code>forrest:css</code> element is used to apply a specific layout via
+     * css. In html for example
+     * 
+     * <pre>
+     *                          &lt;forrest:css url=&quot;pelt.basic.css&quot; media=&quot;screen&quot; theme=&quot;Pelt&quot;/&gt;
+     * </pre>
+     * 
+     * <p>
+     * will be transformed to
+     * </p>
+     * 
+     * <pre>
+     *                          &lt;link media=&quot;screen&quot; href=&quot;../themes/pelt.basic.css&quot; title=&quot;Pelt&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
+     * </pre>
+     */
+    public static final String DISPATCHER_CSS_ELEMENT = "css";
+
+    /**
+     * Each contract can have properties, which are definite e.g. in the
+     * structurer index.fv and used in the contract.
+     * 
+     * <pre>
+     *                          &lt;forrest:contract name=&quot;nav-main-testing&quot; nugget=&quot;cocoon://index.navigation.xml&quot;&gt;
+     *                           &lt;forrest:property name=&quot;nav-main-testing-test1&quot; &gt;Just a test&lt;/forrest:property&gt;
+     *                          &lt;/forrest:contract&gt;
+     * </pre>
+     */
+    public static final String CONTRACT_PROPERTY_ELEMENT = "property";
+
+    public static final String CONTRACT_PROPERTY_ID_ATTRIBUTE = "name";
+
+    private String propertyID;
+
+    private boolean insideProperties = false;
+
+    /**
+     * Convenience object, so we don't need to create an AttributesImpl for
+     * every element.
+     */
+    protected AttributesImpl attributes;
+
+    protected String currentFormat;
+
+    private boolean insideContract = false;
+
+    protected ContractBean contract;
+
+    /**
+     * The namespace used by the transformer for the SAX events filtering. This
+     * either equals to the {@link #defaultNamespaceURI} or to the value set by
+     * the <code>namespaceURI</code> sitemap parameter for the pipeline. Must
+     * never be null.
+     */
+    protected String namespaceURI;
+
+    /**
+     * This is the default namespace used by the transformer. Implementations
+     * should set its value in the constructor. Must never be null.
+     */
+    protected String defaultNamespaceURI;
+
+    private DOMBuilder builder, dispatcherBuilder;
+
+    private DOMUtil domUtil;
+
+    private DocumentFragment frag;
+
+    private Element rootNode;
+
+    private XPathProcessor processor;
+
+    private CachedXPathAPI xpathApi;
+
+    private Document document;
+
+    private NamespaceHelper dispatcher;
+
+    private Map storedPrefixMap;
+
+    private String path = null;
+
+    private boolean recording;
+
+    private DispatcherHelper dispatcherHelper;
+
+    private HashMap domHash;
+
+    /**
+     * Constructor Set the namespace
+     */
+    public DispatcherTransformer() {
+        this.defaultNamespaceURI = DispatcherHelper.DISPATCHER_NAMESPACE_URI;
+    }
+
+    // FIXME: turn on caching!!!
+    /**
+     * Generate the unique key. This key must be unique inside the space of this
+     * component.
+     * 
+     * @return The generated key hashes the src
+     */
+    public Serializable getKey() {
+        return null;
+    }
+
+    // FIXME: turn on caching!!!
+    /**
+     * Generate the validity object.
+     * 
+     * @return The generated validity object or <code>null</code> if the
+     *         component is currently not cacheable.
+     */
+    public SourceValidity getValidity() {
+        return null;
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+     */
+    public void service(ServiceManager manager) throws ServiceException {
+        super.service(manager);
+    }
+
+    /**
+     * @see org.apache.avalon.framework.activity.Disposable#dispose()
+     */
+    public void dispose() {
+        if (null != this.manager) {
+            this.manager = null;
+        }
+        insideProperties = false;
+        super.dispose();
+    }
+
+    /**
+     * Recycle the component
+     */
+    public void recycle() {
+        insideProperties = false;
+        super.recycle();
+    }
+
+    /**
+     * Setup the file generator. Try to get the last modification date of the
+     * source for caching.
+     */
+    public void setup(SourceResolver resolver, Map objectModel, String src,
+            Parameters par) throws ProcessingException, SAXException,
+            IOException {
+        super.setup(resolver, objectModel, src, par);
+        // domUtil = new DOMUtil();
+        /*
+         * DOMImplementation domImpl = new
+         * org.apache.xerces.dom.DOMImplementationImpl(); DocumentType docType =
+         * domImpl.createDocumentType("rootElementName", "public ID", "system
+         * ID"); Document doc = domImpl.createDocument("", "rootElementName",
+         * docType);
+         * 
+         */
+        this.processor = null;
+        this.dispatcherHelper = null;
+        this.xpathApi = null;
+        this.contract = null;
+        try {
+            this.domHash = new HashMap();
+            this.xpathApi = new CachedXPathAPI();
+            this.dispatcherHelper = new DispatcherHelper(manager);
+            this.processor = (XPathProcessor) this.manager
+                    .lookup(XPathProcessor.ROLE);
+        } catch (Exception e) {
+            String error = " dispatcherError:\n Could not set up the dispatcherHelper!\n DispatcherStack: "
+                    + e;
+            getLogger().error(error);
+            throw new ProcessingException(error);
+        }
+        storedPrefixMap = new HashMap();
+        insideProperties = false;
+        this.requestedFormat = parameters.getParameter(
+                STRUCTURER_FORMAT_ATTRIBUTE, null);
+        if (requestedFormat == null) {
+            String error = " dispatcherError:\n You have to set the \"type\" parameter in the sitemap!";
+            getLogger().error(error);
+            throw new ProcessingException(error);
+        }
+    }
+
+    public void startElement(String uri, String name, String raw,
+            Attributes attr) throws SAXException {
+        // Process start element event
+        // Are we inside of properties? If so we need to record the elements.
+        if (this.insideProperties) {
+            if (this.includeNodes) {
+                try {
+                    this.builder.startElement(uri, name, raw, attr);
+                } catch (SAXException e) {
+                    this.insideProperties = false;
+                    String error = " dispatcherError:\n The contract \""
+                            + contract.getContractName()
+                            + "\" has thrown in the property with ID \""
+                            + this.propertyID + "\" following error: " + e;
+                    getLogger().error(error);
+                    throw new SAXException(error);
+                }
+            }
+        } else if (DispatcherHelper.DISPATCHER_NAMESPACE_URI.equals(uri)) {
+            /*
+             * We are in the dispatcher ns.
+             */
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Starting dispatcher element: " + raw);
+            }
+            if (STRUCTURER_ELEMENT.equals(name))
+                structurerProcessingStart(attr);
+            else if (DISPATCHER_HOOK_ELEMENT.equals(name)) {
+                if (this.includeNodes) {
+                    hookProcessingStart(name, raw, attr);
+                }
+            } else if (ContractBean.CONTRACT_ELEMENT.equals(name)) {
+                if (this.includeNodes) {
+                    contractProcessingStart(attr);
+                }
+            } else if (CONTRACT_PROPERTY_ELEMENT.equals(name)) {
+                this.insideProperties = true;
+                if (this.includeNodes)
+                    propertyProcessingStart(uri, name, raw, attr);
+            } else {
+                if (this.includeNodes)
+                    super.startElement(uri, name, raw, attr);
+            }
+        } else {
+            super.startElement(uri, name, raw, attr);
+        }
+    }
+
+    /**
+     * @param name
+     * @param raw
+     * @param attr
+     * @throws DOMException
+     * @throws SAXException
+     */
+    private void hookProcessingStart(String name, String raw, Attributes attr)
+            throws DOMException, SAXException {
+        /* create a DOM node from the current sax event */
+        Element currentElement = dispatcher.getDocument().createElement(name);
+        setAttributesDOM(attr, currentElement);
+        if (path == null || path.equals("")) {
+            path = raw;
+            this.rootNode.appendChild(currentElement);
+        } else {
+            /* calculate, prepare and add node to the dispatcher */
+            try {
+                String tempPath = path + "/" + name;
+                Node xpathNode;
+                String[] xpath = DOMUtil.buildPathArray(path);
+                xpathNode = DOMUtil
+                        .getFirstNodeFromPath(rootNode, xpath, false);
+                if (xpathNode == null)
+                    createXpathNode(attr, tempPath);
+                else
+                    xpathNode.appendChild(currentElement);
+            } catch (Exception e) {
+                String error = " dispatcherError:\n Could not set up xpath!\n\n DispatcherStack:\n "
+                        + e;
+                getLogger().error(error);
+                throw new SAXException(error);
+            }
+            path = path + "/" + name;
+        }
+    }
+
+    /**
+     * @param attr
+     * @param tempPath
+     * @throws ProcessingException
+     * @throws DOMException
+     */
+    private void createXpathNode(Attributes attr, String tempPath)
+            throws ProcessingException, DOMException {
+        Node xpathNode;
+        xpathNode = DOMUtil
+                .selectSingleNode(rootNode, tempPath, this.processor);
+        if (attr != null)
+            setAttributesDOM(attr, xpathNode);
+    }
+
+    /**
+     * @param attr
+     * @param tempPath
+     * @throws ProcessingException
+     * @throws DOMException
+     */
+    private Node createXpathNode(String tempPath) throws ProcessingException,
+            DOMException {
+        Node xpathNode;
+        xpathNode = DOMUtil
+                .selectSingleNode(rootNode, tempPath, this.processor);
+        return xpathNode;
+    }
+
+    /**
+     * @param attr
+     * @param xpathNode
+     * @throws DOMException
+     */
+    private void setAttributesDOM(Attributes attr, Node xpathNode)
+            throws DOMException {
+        for (int i = 0; i < attr.getLength(); i++) {
+            String localName = attr.getLocalName(i);
+            String value = attr.getValue(i);
+            ((Element) xpathNode).setAttribute(localName, value);
+        }
+    }
+
+    public void endElement(String uri, String name, String raw)
+            throws SAXException {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Ending element: " + raw);
+        }
+        // Are we inside of properties? If so we need to record the elements.
+        if (this.insideProperties) {
+            propertyProcessingEnd(uri, name, raw);
+        } else if (DispatcherHelper.DISPATCHER_NAMESPACE_URI.equals(uri)) {
+            if (STRUCTURER_ELEMENT.equals(name)) {
+                structurerProcessingEnd(raw);
+            } else if (ContractBean.CONTRACT_ELEMENT.equals(name)) {
+                if (this.includeNodes)
+                    contractProcessingEnd();
+            } else if (DISPATCHER_HOOK_ELEMENT.equals(name)) {
+                if (this.includeNodes) {
+                    if (path.lastIndexOf("/") > -1)
+                        path = path.substring(0, path.lastIndexOf("/"));
+                    else
+                        path = null;
+                }
+            } else {
+                if (this.includeNodes)
+                    super.endElement(uri, name, raw);
+            }
+        } else {
+            super.endElement(uri, name, raw);
+        }
+    }
+
+    /**
+     * view type="?" Here we check which format we have in the view. That should
+     * be extended to matching the requested format
+     * 
+     * @param attr
+     * @throws SAXException
+     */
+    private void structurerProcessingStart(Attributes attr) throws SAXException {
+        for (int i = 0; i < attr.getLength(); i++) {
+            String localName = attr.getLocalName(i);
+            String value = attr.getValue(i);
+            if (localName.equals(STRUCTURER_FORMAT_ATTRIBUTE)) {
+                currentFormat = value;
+            }
+            if (localName.equals(STRUCTURER_HOOK_XPATH_ATTRIBUTE)) {
+                if ("/".equals(String.valueOf(value.charAt(0)))) {
+                    path = "result" + value;
+                } else {
+                    path = "result/" + value;
+                }
+            }
+        }
+        if (requestedFormat.equals(currentFormat)) {
+            if (path == null)
+                path = "result/";
+            this.includeNodes = true;
+            this.recording = true;
+            try {
+                dispatcherHelper.setNamespaceHelper(
+                        DispatcherHelper.DISPATCHER_NAMESPACE_URI,
+                        DispatcherHelper.DISPATCHER_PREFIX, STRUCTURER_ELEMENT);
+                this.dispatcher = dispatcherHelper.getNamespaceHelper();
+                this.document = dispatcher.getDocument();
+                this.rootNode = document.getDocumentElement();
+                this.rootNode.setAttribute(STRUCTURER_FORMAT_ATTRIBUTE,
+                        currentFormat);
+                this.rootNode.setAttribute(STRUCTURER_HOOK_XPATH_ATTRIBUTE,
+                        path);
+                // we create the path node for the result node
+                DOMUtil.selectSingleNode(rootNode, path, this.processor);
+            } catch (Exception e) {
+                String error = " dispatcherError:\n could not setup dispatcherHelper! \""
+                        + "\n dispatcherErrorStack:\n" + e;
+                getLogger().error(error + e);
+                this.recording = false;
+                throw new SAXException(error + e);
+            }
+
+        } else {
+            path = null; // unset path because we do not process the node
+            this.includeNodes = false;
+            this.recording = false;
+        }
+    }
+
+    /**
+     * @param raw
+     * @throws SAXException
+     */
+    private void structurerProcessingEnd(String raw) throws SAXException {
+        if (this.recording) {
+            XMLUtils.valueOf(new IncludeXMLConsumer(super.xmlConsumer),
+                    this.rootNode);
+            this.recording = false;
+        }
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug(
+                    "Ending \"" + STRUCTURER_ELEMENT + "\" element: " + raw);
+        }
+    }
+
+    /**
+     * We have found a contract. Now we have to prepare a bean to later add it
+     * to the output stream in the endElement.
+     * 
+     * @param attr
+     * @throws SAXException
+     */
+    private void contractProcessingStart(Attributes attr) throws SAXException {
+        this.insideContract = true;
+        try {
+            if (contract == null)
+                contract = new ContractBean(this.manager);
+            else
+                contract.initialize();
+        } catch (ParserConfigurationException e) {
+            throw new SAXException("originally ParserConfigurationException"
+                    + e);
+        }
+        for (int i = 0; i < attr.getLength(); i++) {
+            String localName = attr.getLocalName(i);
+            String value = attr.getValue(i);
+            if (ContractBean.CONTRACT_ID_ATTRIBUTE.equals(localName)) {
+                // getting the contract name
+                contract.setContractName(value);
+                String contractUri = ContractBean.CONTRACT_RESOLVE_PREFIX + "."
+                        + currentFormat + "." + value;
+                try {
+                    Document doc = org.apache.forrest.dispatcher.util.SourceUtil
+                            .readDOM(contractUri, this.manager);
+                    contract.setContractImpl(doc);
+                    // contract.setContractImpl(contractUri);
+                } catch (Exception e) {
+                    String error = " dispatcherError:\n The contract \""
+                            + contract.getContractName()
+                            + "\" has thrown following errorStack by resolving the implementation from \""
+                            + contractUri + "\".\n dispatcherErrorStack:\n";
+                    getLogger().error(error + e);
+                    throw new SAXException(error + e);
+                }
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug(
+                            "DISPATCHER_CONTRACT_ID_ATTRIBUTE" + "-->"
+                                    + localName + "\n" + "value" + "-->"
+                                    + value);
+                }
+            } else if (ContractBean.CONTRACT_NUGGET_ATTRIBUTE.equals(localName)) {
+                // contract is a nugget-contract
+                contract.setNugget(true);
+                try {
+                    Document doc = org.apache.forrest.dispatcher.util.SourceUtil
+                            .readDOM(value, this.manager);
+                    contract.setContractRawData(doc);
+                    // contract.setNuggetUri(value);
+                } catch (Exception e) {
+                    String error = " dispatcherError:\n The contract \""
+                            + contract.getContractName()
+                            + "\" has thrown following errorStack by resolving raw data from \""
+                            + value + "\".\n dispatcherErrorStack:\n ";
+                    getLogger().error(error + e);
+                    throw new SAXException(error + e);
+                }
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug(
+                            "ContractBean.CONTRACT_NUGGET_ATTRIBUTE" + "-->"
+                                    + localName + "\n" + "value" + "-->"
+                                    + value);
+                }
+            } else {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug(
+                            "localName" + "-->" + localName
+                                    + " not implemented");
+                }
+            }
+        }
+        /*
+         * if we do not have a nugget add a foo element to the raw data to
+         * invoke the transformation.
+         */
+        if (!contract.isNugget()) {
+            Document foo;
+            try {
+                foo = dispatcherHelper.createDocument("foo");
+                contract.setContractRawData(foo);
+            } catch (Exception e) {
+                String error = " dispatcherError:\n The contract \""
+                        + contract.getContractName()
+                        + "\" has thrown following errorStack by creating the dummy foo document."
+                        + ".\n dispatcherErrorStack:\n ";
+                getLogger().error(error + e);
+                throw new SAXException(error + e);
+            }
+            /*
+             * Document fooDoc =// (Document)
+             * dispatcherHelper.getNamespaceHelper().getDocument();
+             * fooDoc.createElement("foo");
+             * contract.getFooData().getOwnerDocument();
+             */
+        }
+    }
+
+    /**
+     * @throws SAXException
+     */
+    private void contractProcessingEnd() throws SAXException {
+        try {
+            contract.setContractResultData();
+            Document node = (Document) contract.getContractResultData()
+                    .getNode();
+            Document root = this.rootNode.getOwnerDocument();
+            /*
+             * debug code - uncomment it if you need it! will output the
+             * contract resulting data to sysout
+             * 
+             * DOMSource source = new DOMSource(node); StreamResult result = new
+             * StreamResult(System.out);
+             * contract.getContractTransformer().transform(source, result);
+             */
+
+            /*
+             * append this node to the current path after testing where there is
+             * a fixed location for the contract content. If so then add it
+             * there.
+             */
+            NodeList contentChildren = node.getElementsByTagNameNS(
+                    DispatcherHelper.DISPATCHER_NAMESPACE_URI, "part");
+            for (int i = 0; i < contentChildren.getLength(); i++) {
+                Element contentChild = (Element) contentChildren.item(i);
+                if (contentChild != null) {
+                    String location = contentChild.getAttribute("xpath");
+                    if (location.equals("") | location == null) {
+                        String[] xpath = DOMUtil.buildPathArray(path);
+                        Node xpathNode = DOMUtil.getFirstNodeFromPath(rootNode,
+                                xpath, false);
+                        if (xpathNode != null) {
+                            if (node.hasChildNodes()) {
+                                Node toMove = root.importNode(contentChild,
+                                        true);
+                                xpathNode.appendChild(toMove);
+                            }
+                        }
+                    } else {
+                        if (location.charAt(0) == '/')
+                            location = "result" + location;
+                        else
+                            location = "result/" + location;
+                        Node xpathNode;
+                        String[] xpath = DOMUtil.buildPathArray(location);
+                        xpathNode = DOMUtil.getFirstNodeFromPath(rootNode,
+                                xpath, false);
+                        if (xpathNode != null) {
+                            if (node.hasChildNodes()) {
+                                Node toMove = root.importNode(contentChild,
+                                        true);
+                                xpathNode.appendChild(toMove);
+                            }
+                        } else {
+                            xpathNode = createXpathNode(location);
+                            if (node.hasChildNodes()) {
+                                Node toMove = root.importNode(contentChild,
+                                        true);
+                                xpathNode.appendChild(toMove);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            String error = " dispatcherError:\n The contract \""
+                    + contract.getContractName()
+                    + "\" has thrown following error while trying to transform the final markup: "
+                    + e;
+            getLogger().error(error);
+            throw new SAXException(error);
+        } finally {
+            this.insideContract = false;
+            this.contract.recycle();
+        }
+    }
+
+    /**
+     * @param uri
+     * @param name
+     * @param raw
+     * @param attr
+     * @throws SAXException
+     */
+    private void propertyProcessingStart(String uri, String name, String raw,
+            Attributes attr) throws SAXException {
+        for (int i = 0; i < attr.getLength(); i++) {
+            String localName = attr.getLocalName(i);
+            String value = attr.getValue(i);
+            if (CONTRACT_PROPERTY_ID_ATTRIBUTE.equals(localName)) {
+                this.propertyID = value;
+            }
+        }
+        if (this.propertyID.equals("") | this.propertyID == null) {
+            String error = " dispatcherError:\n The contract \""
+                    + contract.getContractName()
+                    + "\" has no identifier attribute \""
+                    + CONTRACT_PROPERTY_ID_ATTRIBUTE + "\" in the " + raw;
+            getLogger().error(error);
+            throw new SAXException(error);
+        }
+        this.builder = new DOMBuilder();
+        this.builder.startDocument();
+        launchStoredMappings();
+        this.builder.startElement(uri, name, raw, attr);
+    }
+
+    /**
+     * @param uri
+     * @param name
+     * @param raw
+     * @throws SAXException
+     */
+    private void propertyProcessingEnd(String uri, String name, String raw)
+            throws SAXException {
+        if (CONTRACT_PROPERTY_ELEMENT.equals(name)) {
+            this.insideProperties = false;
+            if (this.includeNodes) {
+                this.builder.endElement(uri, name, raw);
+                this.builder.endDocument();
+                if (getLogger().isDebugEnabled()) {
+                    getLogger()
+                            .debug(
+                                    "DispatcherTransformer: putting DOM tree into the contract transformer");
+                }
+                Transformer transformer = contract.getContractTransformer();
+                transformer.setParameter(this.propertyID, this.builder
+                        .getDocument().getFirstChild());
+                contract.setContractTransformer(transformer);
+                this.propertyID = "";
+                contract.setHasProperties(true);
+                if (getLogger().isDebugEnabled()) {
+                    getLogger()
+                            .debug(
+                                    "DispatcherTransformer: DOM tree is in the contract transformer");
+                }
+                this.builder = null;
+            }
+        } else {
+            if (this.includeNodes)
+                this.builder.endElement(uri, name, raw);
+        }
+    }
+
+    public void characters(char c[], int start, int len) throws SAXException {
+        if (this.insideProperties) {
+            if (this.includeNodes)
+                this.builder.characters(c, start, len);
+        } else {
+            if (this.includeNodes)
+                super.contentHandler.characters(c, start, len);
+        }
+    }
+
+    public void startCDATA() throws SAXException {
+        if (this.insideProperties) {
+            if (this.includeNodes)
+                this.builder.startCDATA();
+        } else {
+            if (this.includeNodes)
+                super.lexicalHandler.startCDATA();
+        }
+    }
+
+    public void endCDATA() throws SAXException {
+        if (this.insideProperties) {
+            if (this.includeNodes)
+                this.builder.endCDATA();
+        } else {
+            if (this.includeNodes)
+                super.lexicalHandler.endCDATA();
+        }
+    }
+
+    /** BEGIN SAX ContentHandler handlers * */
+
+    public void startPrefixMapping(String prefix, String uri)
+            throws SAXException {
+        super.startPrefixMapping(prefix, uri);
+        if (this.insideProperties) {
+            if (this.includeNodes)
+                this.builder.startPrefixMapping(prefix, uri);
+        } else {
+            storePrefixMapping(prefix, uri);
+        }
+    }
+
+    /** END SAX ContentHandler handlers * */
+
+    protected void storePrefixMapping(String prefix, String uri) {
+        storedPrefixMap.put(prefix, uri);
+    }
+
+    protected void launchStoredMappings() throws SAXException {
+        Iterator it = storedPrefixMap.keySet().iterator();
+        while (it.hasNext()) {
+            String pre = (String) it.next();
+            String uri = (String) storedPrefixMap.get(pre);
+            getLogger().debug(
+                    "WriteSessionTransformer: launching prefix mapping[ pre: "
+                            + pre + " uri: " + uri + " ]");
+            this.builder.startPrefixMapping(pre, uri);
+        }
+    }
+
+    protected void launchStoredMappingsDispatcher() throws SAXException {
+        Iterator it = storedPrefixMap.keySet().iterator();
+        while (it.hasNext()) {
+            String pre = (String) it.next();
+            String uri = (String) storedPrefixMap.get(pre);
+            getLogger().debug(
+                    "WriteSessionTransformer: launching prefix mapping[ pre: "
+                            + pre + " uri: " + uri + " ]");
+            this.dispatcherBuilder.startPrefixMapping(pre, uri);
+        }
+    }
+
+}

Propchange: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/util/SourceUtil.java
URL: http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/util/SourceUtil.java?rev=349923&view=auto
==============================================================================
--- forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/util/SourceUtil.java (added)
+++ forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/util/SourceUtil.java Wed Nov 30 03:14:46 2005
@@ -0,0 +1,52 @@
+package org.apache.forrest.dispatcher.util;
+
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceNotFoundException;
+import org.apache.lenya.xml.DocumentHelper;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public class SourceUtil {
+    /**
+     * Reads a DOM from a source.
+     * @param sourceUri The source URI.
+     * @param manager The service manager.
+     * @return A document or <code>null</code> if the source does not exist.
+     * @throws ServiceException if an error occurs.
+     * @throws SourceNotFoundException if an error occurs.
+     * @throws ParserConfigurationException if an error occurs.
+     * @throws SAXException if an error occurs.
+     * @throws IOException if an error occurs.
+     */
+    public static Document readDOM(String sourceUri, ServiceManager manager)
+            throws ServiceException, SourceNotFoundException, ParserConfigurationException,
+            SAXException, IOException {
+        SourceResolver resolver = null;
+        Source source = null;
+        Document document = null;
+        try {
+
+            resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
+            source = resolver.resolveURI(sourceUri);
+
+            if (source.exists()) {
+                document = DocumentHelper.readDocument(source.getInputStream());
+            }
+        } finally {
+            if (resolver != null) {
+                if (source != null) {
+                    resolver.release(source);
+                }
+                manager.release(resolver);
+            }
+        }
+        return document;
+    }
+}

Propchange: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/util/SourceUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/DocumentHelper.java
URL: http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/DocumentHelper.java?rev=349923&view=auto
==============================================================================
--- forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/DocumentHelper.java (added)
+++ forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/DocumentHelper.java Wed Nov 30 03:14:46 2005
@@ -0,0 +1,446 @@
+/*
+ * Copyright  1999-2005 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.lenya.xml;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.xml.resolver.tools.CatalogResolver;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+import org.xml.sax.SAXException;
+
+/**
+ * Various utility methods to work with JAXP.
+ * @version $Id: DocumentHelper.java 264963 2005-08-31 07:58:45Z andreas $
+ */
+public class DocumentHelper {
+    /**
+     * Creates a non-validating and namespace-aware DocumentBuilder.
+     * @return A new DocumentBuilder object.
+     * @throws ParserConfigurationException if an error occurs
+     */
+    public static DocumentBuilder createBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+
+        CatalogResolver cr = new CatalogResolver();
+        builder.setEntityResolver(cr);
+        return builder;
+    }
+
+    /**
+     * Creates a document. A xmlns:prefix="namespaceUri" attribute is added to
+     * the document element.
+     * @param namespaceUri The namespace URL of the root element.
+     * @param qualifiedName The qualified name of the root element.
+     * @param documentType The type of document to be created or null. When
+     *            doctype is not null, its Node.ownerDocument attribute is set
+     *            to the document being created.
+     * @return A new Document object.
+     * @throws DOMException if an error occurs
+     * @throws ParserConfigurationException if an error occurs
+     * @see org.w3c.dom.DOMImplementation#createDocument(String, String,
+     *      DocumentType)
+     */
+    public static Document createDocument(String namespaceUri, String qualifiedName,
+            DocumentType documentType) throws DOMException, ParserConfigurationException {
+        DocumentBuilder builder = createBuilder();
+        Document document = builder.getDOMImplementation().createDocument(namespaceUri,
+                qualifiedName,
+                documentType);
+
+        // add xmlns:prefix attribute
+        String name = "xmlns";
+        int index = qualifiedName.indexOf(":");
+
+        if (index > -1) {
+            name += (":" + qualifiedName.substring(0, index));
+        }
+
+        document.getDocumentElement().setAttributeNS("http://www.w3.org/2000/xmlns/",
+                name,
+                namespaceUri);
+
+        return document;
+    }
+
+    /**
+     * Reads a document from a file.
+     * @return A document.
+     * @param file The file to load the document from.
+     * @throws ParserConfigurationException if an error occurs
+     * @throws SAXException if an error occurs
+     * @throws IOException if an error occurs
+     */
+    public static Document readDocument(File file) throws ParserConfigurationException,
+            SAXException, IOException {
+        DocumentBuilder builder = createBuilder();
+        return builder.parse(file);
+    }
+
+    /**
+     * Reads a document from a URL.
+     * @return A document.
+     * @param url The URL to load the document from.
+     * @throws ParserConfigurationException if an error occurs
+     * @throws SAXException if an error occurs
+     * @throws IOException if an error occurs
+     */
+    public static Document readDocument(URL url) throws ParserConfigurationException, SAXException,
+            IOException {
+        DocumentBuilder builder = createBuilder();
+        return builder.parse(url.toString());
+    }
+
+    /**
+     * Reads a document from a URI.
+     * @return A document.
+     * @param uri The URI to load the document from.
+     * @throws ParserConfigurationException if an error occurs
+     * @throws SAXException if an error occurs
+     * @throws IOException if an error occurs
+     */
+    public static Document readDocument(URI uri) throws ParserConfigurationException, SAXException,
+            IOException {
+        DocumentBuilder builder = createBuilder();
+        return builder.parse(uri.toString());
+    }
+
+    /**
+     * Reads a document from a string.
+     * @return A document.
+     * @param string The string to load the document from.
+     * @throws ParserConfigurationException if an error occurs
+     * @throws SAXException if an error occurs
+     * @throws IOException if an error occurs
+     */
+    public static Document readDocument(String string) throws ParserConfigurationException,
+            SAXException, IOException {
+        DocumentBuilder builder = createBuilder();
+        return builder.parse(string);
+    }
+
+    /**
+     * Reads a document from an input stream.
+     * @return A document.
+     * @param stream The input stream to load the document from.
+     * @throws ParserConfigurationException if an error occurs
+     * @throws SAXException if an error occurs
+     * @throws IOException if an error occurs
+     */
+    public static Document readDocument(InputStream stream) throws ParserConfigurationException,
+            SAXException, IOException {
+        DocumentBuilder builder = createBuilder();
+        return builder.parse(stream);
+    }
+
+    /**
+     * Writes a document to a file. A new file is created if it does not exist.
+     * @param document The document to save.
+     * @param file The file to save the document to.
+     * @throws IOException if an error occurs
+     * @throws TransformerConfigurationException if an error occurs
+     * @throws TransformerException if an error occurs
+     */
+    public static void writeDocument(Document document, File file)
+            throws TransformerConfigurationException, TransformerException, IOException {
+        // sanity checks
+        if (document == null)
+            throw new IllegalArgumentException("illegal usage, parameter document may not be null");
+        if (file == null)
+            throw new IllegalArgumentException("illegal usage, parameter file may not be null");
+
+        file.getParentFile().mkdirs();
+        file.createNewFile();
+
+        DOMSource source = new DOMSource(document);
+        StreamResult result = new StreamResult(file);
+        getTransformer(document.getDoctype()).transform(source, result);
+    }
+
+    /**
+     * Writes a document to a writer.
+     * @param document The document to write.
+     * @param writer The writer to write the document to.
+     * @throws TransformerConfigurationException if an error occurs
+     * @throws TransformerException if an error occurs
+     */
+    public static void writeDocument(Document document, Writer writer)
+            throws TransformerConfigurationException, TransformerException {
+
+        // sanity checks
+        if (document == null)
+            throw new IllegalArgumentException("illegal usage of DocumentHelper::writeDocument(), parameter document may not be null");
+
+        DOMSource source = new DOMSource(document);
+        StreamResult result = new StreamResult(writer);
+        getTransformer(document.getDoctype()).transform(source, result);
+    }
+
+    /**
+     * Get the transformer.
+     * @param documentType the document type
+     * @return a transformer
+     * @throws TransformerConfigurationException if an error occurs
+     */
+    protected static Transformer getTransformer(DocumentType documentType)
+            throws TransformerConfigurationException {
+        TransformerFactory factory = TransformerFactory.newInstance();
+        Transformer transformer = factory.newTransformer();
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+
+        if (documentType != null) {
+            if (documentType.getPublicId() != null)
+                transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, documentType.getPublicId());
+            if (documentType.getSystemId() != null)
+                transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, documentType.getSystemId());
+        }
+
+        return transformer;
+    }
+
+    /**
+     * Creates a document type.
+     * @param qualifiedName The qualified name of the document type.
+     * @param publicId The public identifier.
+     * @param systemId The system identifier.
+     * @return the document type
+     * @throws ParserConfigurationException if an error occurs
+     * @see org.w3c.dom.DOMImplementation#createDocumentType(java.lang.String,
+     *      java.lang.String, java.lang.String)
+     */
+    public DocumentType createDocumentType(String qualifiedName, String publicId, String systemId)
+            throws ParserConfigurationException {
+        DocumentBuilder builder = createBuilder();
+
+        return builder.getDOMImplementation().createDocumentType(qualifiedName, publicId, systemId);
+    }
+
+    /**
+     * Returns the first child element of an element that belong to a certain
+     * namespace or <code>null</code> if none exists.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @return The first child element or <code>null</code> if none exists.
+     */
+    public static Element getFirstChild(Element element, String namespaceUri) {
+        return getFirstChild(element, namespaceUri, "*");
+    }
+
+    /**
+     * Returns the first child element of an element that belongs to a certain
+     * namespace and has a certain local name or <code>null</code> if none
+     * exists.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @param localName The local name of the children.
+     * @return The child element or <code>null</code> if none exists.
+     */
+    public static Element getFirstChild(Element element, String namespaceUri, String localName) {
+        Element[] children = getChildren(element, namespaceUri, localName);
+
+        if (children.length > 0) {
+            return children[0];
+        }
+        return null;
+    }
+
+    /**
+     * Returns all child elements of an element, regardless of the namespace.
+     * @param element The parent element.
+     * @return The child elements.
+     */
+    public static Element[] getChildren(Element element) {
+        List childElements = new ArrayList();
+        NodeList children = element.getElementsByTagName("*");
+
+        for (int i = 0; i < children.getLength(); i++) {
+            if (children.item(i).getParentNode() == element) {
+                childElements.add(children.item(i));
+            }
+        }
+
+        return (Element[]) childElements.toArray(new Element[childElements.size()]);
+    }
+
+    /**
+     * Returns all child elements of an element that belong to a certain
+     * namespace.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @return The child elements.
+     */
+    public static Element[] getChildren(Element element, String namespaceUri) {
+        return getChildren(element, namespaceUri, "*");
+    }
+
+    /**
+     * Returns all child elements of an element that belong to a certain
+     * namespace and have a certain local name.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @param localName The local name of the children.
+     * @return The child elements.
+     */
+    public static Element[] getChildren(Element element, String namespaceUri, String localName) {
+        List childElements = new ArrayList();
+        NodeList children = element.getElementsByTagNameNS(namespaceUri, localName);
+
+        for (int i = 0; i < children.getLength(); i++) {
+            if (children.item(i).getParentNode() == element) {
+                childElements.add(children.item(i));
+            }
+        }
+
+        return (Element[]) childElements.toArray(new Element[childElements.size()]);
+    }
+
+    /**
+     * Returns the text inside an element. Only the child text nodes of this
+     * element are collected.
+     * @param element The element.
+     * @return The text inside the element.
+     */
+    public static String getSimpleElementText(Element element) {
+        StringBuffer buffer = new StringBuffer();
+        NodeList children = element.getChildNodes();
+
+        for (int i = 0; i < children.getLength(); i++) {
+            Node child = children.item(i);
+
+            if (child instanceof Text) {
+                buffer.append(child.getNodeValue());
+            }
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Replaces all child nodes of an element by a single text node.
+     * @param element The element.
+     * @param text The text to insert.
+     */
+    public static void setSimpleElementText(Element element, String text) {
+        NodeList children = element.getChildNodes();
+
+        for (int i = 0; i < children.getLength(); i++) {
+            Node child = children.item(i);
+            element.removeChild(child);
+        }
+
+        Node textNode = element.getOwnerDocument().createTextNode(text);
+        element.appendChild(textNode);
+    }
+
+    /**
+     * Returns all following sibling elements of an element that belong to a
+     * certain namespace.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @return The following sibling elements.
+     */
+    public static Element[] getNextSiblings(Element element, String namespaceUri) {
+        return getNextSiblings(element, namespaceUri, "*");
+    }
+
+    /**
+     * Returns all following sibling elements of an element that belong to a
+     * certain namespace. and have a certain local name.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @param localName The local name of the children.
+     * @return The following sibling elements.
+     */
+    public static Element[] getNextSiblings(Element element, String namespaceUri, String localName) {
+        List childElements = new ArrayList();
+        Element parent = (Element) element.getParentNode();
+        Element[] children = getChildren(parent, namespaceUri, localName);
+
+        int l = children.length;
+        for (int i = 0; i < children.length; i++) {
+            if (children[i] == element) {
+                l = i;
+            }
+            if (i > l) {
+                childElements.add(children[i]);
+            }
+        }
+
+        return (Element[]) childElements.toArray(new Element[childElements.size()]);
+    }
+
+    /**
+     * Returns all preceding sibling elements of an element that belong to a
+     * certain namespace.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @return The preceding sibling elements.
+     */
+    public static Element[] getPrecedingSiblings(Element element, String namespaceUri) {
+        return getPrecedingSiblings(element, namespaceUri, "*");
+    }
+
+    /**
+     * Returns all preceding sibling elements of an element that belong to a
+     * certain namespace. and have a certain local name.
+     * @param element The parent element.
+     * @param namespaceUri The namespace that the childen must belong to.
+     * @param localName The local name of the children.
+     * @return The preceding sibling elements.
+     */
+    public static Element[] getPrecedingSiblings(Element element, String namespaceUri,
+            String localName) {
+        List childElements = new ArrayList();
+        Element parent = (Element) element.getParentNode();
+        Element[] children = getChildren(parent, namespaceUri, localName);
+
+        int i = 0;
+        while (children[i] != element && i < children.length) {
+            childElements.add(children[i]);
+            i++;
+        }
+
+        return (Element[]) childElements.toArray(new Element[childElements.size()]);
+    }
+}

Propchange: forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/lenya/xml/DocumentHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native