<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="wicket-integration">
  <title>Wicket Integration</title>
  
  <section id="wicket.introduction">
    <title>Introduction</title>
    <para>
      Apache Wicket has become on of the most popular web frameworks of these days.
      Especially developers with a strong Java background benefit from its Java-centric approach because all
      object-oriented features can be applied. This results in highly reusable code.
    </para>
    <para>
      On the other side Cocoon implementing the pipe/filter pattern has its merits in the 
      field of generating resources in different output formats. 
    </para>
    <para>
      The Cocoon-Wicket integration module bridges between those two web application frameworks
      in order to use the strenghts of both. This integration supports the integration of
      Cocoon into Wicket as well as the integration of Wicket into Cocoon.
    </para>
    <para><emphasis>Note:</emphasis> This is <emphasis>not</emphasis> an introduction into Apache Wicket. This documentation
      explains to the experienced Wicket user what needs to be done to integrate Cocoon 3 into a Wicket application.
    </para>        
  </section>

  <section id="wicket.wicket-cocoon-integration">
    <title>Integrate Cocoon into Wicket</title>
    <para>
      The integration of Cocoon into Wicket is available in several ways:  
      <itemizedlist>
        <listitem>
          <para>A <emphasis>Cocoon sitemap</emphasis> can be mounted as 
          <ulink url="http://wicket.apache.org/docs/1.4/org/apache/wicket/request/target/coding/IRequestTargetUrlCodingStrategy.html"><literal>IRequestTargetUrlCodingStrategy</literal></ulink></para>
        </listitem>
        <listitem>
          <para>A single <emphasis>Cocoon pipeline</emphasis> can be mounted as <ulink url="http://wicket.apache.org/docs/1.4/org/apache/wicket/request/target/coding/IRequestTargetUrlCodingStrategy.html"><literal>IRequestTargetUrlCodingStrategy</literal></ulink> (not implemented yet)</para>
        </listitem>
        <listitem>
          <para>A <emphasis>CocoonSAXPipeline Wicket component</emphasis> can be added to a 
          <ulink url="http://wicket.apache.org/docs/1.4/org/apache/wicket/markup/html/WebPage.html"><literal>WebPage</literal></ulink></para>
        </listitem>
      </itemizedlist>      
    </para>
    <para>
      Whatever approach is chosen, the first step is adding <literal>cocoon-wicket</literal> and all
      its transitive dependencies to your project's classpath:
    </para>
    <programlisting language="xml"><![CDATA[<dependency>
  <groupId>org.apache.cocoon.wicket</groupId>
  <artifactId>cocoon-wicket</artifactId>
  <version>3.0.0-alpha-2</version>
</dependency>]]></programlisting>    

    <section id="wicket.wicket-cocoon-integration.sitemap">
      <title>Mount a Cocoon sitemap</title>
      <para>
        Mounting in the context of Wicket means a class implementing <ulink url="http://wicket.apache.org/docs/1.4/org/apache/wicket/request/target/coding/IRequestTargetUrlCodingStrategy.html"><literal>IRequestTargetUrlCodingStrategy</literal></ulink>
        is added to a Wicket web application. This interface is implemented by <literal>CocoonSitemap</literal>:          
      </para>
      <programlistingco>
        <areaspec>
          <area id="wicket.wicket-cocoon-integration.sitemap.mount" coords="9" />
        </areaspec>      
      <programlisting language="java"><![CDATA[import org.apache.cocoon.wicket.target.CocoonSitemap;
import org.apache.wicket.protocol.http.WebApplication;

public class SomeWebApplication extends WebApplication {

    @Override
    protected void init() {
        ...
        this.mount(new CocoonSitemap("/sitemap", "/sitemap.xmap.xml"));
        ...
    }
}]]></programlisting>
       <calloutlist>
         <callout arearefs="wicket.wicket-cocoon-integration.sitemap.mount">
           <para>
             The first parameter is the mount path which is a part of the request URI that should be
             handled by <literal>CocoonSitemap</literal>. The second parameter is the location of
             the sitemap relativ to the servlet context.  
           </para>
         </callout>
       </calloutlist>
     </programlistingco>   
     <para>
       Additionally you have to make sure that all Spring bean definitions provided by the Cocoon modules are
       loaded into the web application's Spring application context. Cocoon's own bean definitions are located in
       <literal>META-INF/cocoon/spring/*.xml</literal>.
     </para>
     <para>
       The simplest solution for this task is referring to the Cocoon Spring Configurator in your main Spring application context, 
       which is usually located in <literal>[servlet-context-base-directory]/WEB-INF/applicationContext.xml</literal>. It will
       automatically load all bean definitions located in <literal>META-INF/cocoon/spring/*.xml</literal> of all libraries
       on the classpath.
       The <ulink url="http://cocoon.apache.org/subprojects/configuration/1.0/spring-configurator/2.1/1303_1_1.html">
       Cocoon Spring Configurator documentation</ulink> contains further details.
     </para>   
     <para>
       Note that the Spring Configurator is one of the transitive dependencies of <literal>cocoon-wicket</literal>.
     </para>
     <para>
       That's it! Everything else is the same as using Cocoon 3 outside of Wicket except that the
       <literal>servlet:/</literal> protocol won't work in this environment.
     </para>
    </section>
    
    <section id="wicket.wicket-cocoon-integration.pipeline">
      <title>Mount a Cocoon pipeline</title>
      <para>
        <emphasis>NOTE: This hasn't been implemented yet!</emphasis>
      </para>
      <para>
        Mounting a Cocoon pipeline follows the same idea as mounting a whole sitemap. However, it's only a single pipeline
        that is added to Wicket's URI path and that this can be done without having to write any XML.
      </para>
      <para>
        All that needs to be done is subclassing from <literal>org.apache.cocoon.wicket.AbstractCocoonPipeline</literal>
        and implementing its <literal>addComponents</literal> method:
      </para>
      <programlistingco>
        <areaspec>
          <area id="wicket.wicket-cocoon-integration.pipeline.mount" coords="9" />
        </areaspec>      
        <programlisting language="java"><![CDATA[import com.mycompany.MyCocoonPipeline;
import org.apache.wicket.protocol.http.WebApplication;

public class SomeWebApplication extends WebApplication 

    @Override
    protected void init() {
        ...
        this.mount(new MyCocoonPipeline("/my-pipeline"));
        ...
    }
}]]></programlisting>
       <calloutlist>
         <callout arearefs="wicket.wicket-cocoon-integration.pipeline.mount">
           <para>
             The only parameter is the path where the pipeline should be be mounted by Wicket.  
           </para>
         </callout>
       </calloutlist>
     </programlistingco>
      <para>
        In <literal>MyCocoonPipeline</literal> all that needs to be done is subclassing from 
        <literal>org.apache.cocoon.wicket.AbstractCocoonPipeline</literal> and implementing its abstract method 
        <literal>addComponents</literal>:
      </para>       
      <programlistingco>
        <areaspec>
          <area id="wicket.wicket-cocoon-integration.pipeline.def" coords="9" />
        </areaspec>      
      <programlisting language="java"><![CDATA[package com.mycompany;
import org.apache.cocoon.wicket.AbstractCocoonPipeline;
import org.apache.wicket.protocol.http.WebApplication;

public class MyCocoonPipeline extends 
    org.apache.cocoon.wicket.AbstractCocoonPipeline<SAXPipelineComponent>

    @Override
    protected void addComponents() {
        this.addComponent(new FileGenerator(this.getClass().getResource("test.xml")));
        this.addComponent(new XSLTTransformer(this.getClass().getResource("test.xsl")));        
        this.addComponent(new XMLSerializer());        
    }
}]]></programlisting>
       <calloutlist>
         <callout arearefs="wicket.wicket-cocoon-integration.pipeline.def">
           <para>
             Add all pipeline components that are required.  
           </para>
         </callout>
       </calloutlist>
     </programlistingco>      
    </section>    
    
    <section id="wicket.wicket-cocoon-integration.component">
      <title>CocoonSAXPipeline Wicket component</title>
      <para>
        The third alternative of using Cocoon in Wicket is adding a Cocoon pipeline as 
        <ulink url="http://wicket.apache.org/docs/1.4/org/apache/wicket/markup/html/WebComponent.html"><literal>WebComponent</literal></ulink>.
        This is as simple as instantiating <literal>CocoonSAXPipeline</literal> and adding
        all generators and transformers that are required: 
      </para>
      <programlistingco>
        <areaspec>
          <area id="wicket.wicket-cocoon-integration.component.new" coords="11" />
          <area id="wicket.wicket-cocoon-integration.component.add" coords="13" />
        </areaspec>      
      <programlisting language="java"><![CDATA[import org.apache.cocoon.pipeline.NonCachingPipeline;
import org.apache.cocoon.sax.SAXPipelineComponent;
import org.apache.cocoon.sax.component.StringGenerator;
import org.apache.cocoon.sax.component.XSLTTransformer;
import org.apache.cocoon.wicket.CocoonSAXPipeline;
import org.apache.wicket.markup.html.WebPage;
      
    public class Homepage extends WebPage {

    public Homepage() {
        CocoonSAXPipeline pipeline = new CocoonSAXPipeline("cocoon-pipeline-component",
                new NonCachingPipeline<SAXPipelineComponent>());
        pipeline.addComponent(new StringGenerator("<b>hello, Cocoon!</b>"));
        pipeline.addComponent(new XSLTTransformer(
                this.getClass().getResource("transform.xslt")));
        this.add(pipeline);
    }
}
]]></programlisting>
       <calloutlist>
         <callout arearefs="wicket.wicket-cocoon-integration.component.new">
           <para>
             Instantiate the component  
           </para>
         </callout>
         <callout arearefs="wicket.wicket-cocoon-integration.component.add">
           <para>
             Adding SAX pipeline components
           </para>
         </callout>
       </calloutlist>
     </programlistingco>  
     <para>
       The pipeline's result is added to the HTML produced by this page. This is the reason
       why only generators and transformers can be added to this component because the
       pipeline is always serialized as XHTML. An XHTMLSerializer is added implicitly to
       each pipeline.
     </para>       
    </section>
  </section>
  
  <section id="wicket.cocoon-wicket-integration">
    <title>Integrate Wicket into Cocoon</title>
    <para>
      <emphasis>Note:</emphasis> The integration of Wicket into Cocoon os mostly a proof of concept. 
      It is experimental and has neither been optimized nor tested yet.
    </para>
    <para>
      The integration of Wicket into Cocoon means that the output of Wicket is added to the content stream of a pipeline.
      The currently available solution is a reader but alternatively a generator or a transformer would offer an even more
      alternatives. 
    </para>
    <para>
      As pointed out for the Wicket-Cocoon integration, the first step in every case is adding <literal>cocoon-wicket</literal> and all
      its transitive dependencies to your project's classpath:
    </para>
    <programlisting language="xml"><![CDATA[<dependency>
  <groupId>org.apache.cocoon.wicket</groupId>
  <artifactId>cocoon-wicket</artifactId>
  <version>3.0.0-alpha-2</version>
</dependency>]]></programlisting>    
    <section id="wicket.cocoon-wicket.reader">
      <title>Wicket reader</title>
      <para>
        By using the Wicket reader a servlet request is referred to a Wicket web application. The current implementation
        expects exactly one Wicket web application being available as Spring bean:
      </para>
    <programlisting language="xml"><![CDATA[<beans>
  <bean id="wicketWebapp" 
    class="com.mycompany.MyWicketWebapp"/>
</beans>]]></programlisting>          
      <para>
        By adding the bean definition file as resource into <literal>META-INF/cocoon/spring</literal> the 
        Wicket web application bean will be loaded automatically.
      </para>
      <para>
        Then the Wicket reader has be to used in the sitemap:
      </para>
      <programlistingco>
        <areaspec>
          <area id="wicket.cocoon-wicket-integration.pipeline.match" coords="5" />
          <area id="wicket.cocoon-wicket-integration.pipeline.reader" coords="6" />
        </areaspec>      
        <programlisting language="xml"><![CDATA[<map:sitemap>
  <map:pipelines>    
    <map:pipeline type="noncaching">
      <map:match wildcard="my-wicket-app/**">
        <map:read type="wicket" base-path="/my-wicket-app" />
      </map:match>
    </map:pipeline>
  </map:pipelines>
</map:sitemap>]]></programlisting>
       <calloutlist>
         <callout arearefs="wicket.cocoon-wicket-integration.pipeline.match">
           <para>
             Use a <literal>**</literal> wildcard to match all requests that start with
             <literal>my-wicket-app</literal>.           
           </para>
         </callout>
         <callout arearefs="wicket.cocoon-wicket-integration.pipeline.reader">
           <para>
             The name of the reader is <literal>wicket</literal>. It's also required
             to define the base path so that Wicket can calclulate realtive URLs correctly.
           </para>
         </callout>
       </calloutlist>
     </programlistingco>    
    </section>    
  </section>
</chapter>
