<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gridshore &#187; hippo</title>
	<atom:link href="http://www.gridshore.nl/tag/hippo/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gridshore.nl</link>
	<description>A weblog about software engineering, Architecture, Technology an other things we like.</description>
	<lastBuildDate>Tue, 13 Dec 2011 15:36:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Creating an rss feed using the latest features of Hippo</title>
		<link>http://www.gridshore.nl/2011/12/13/creating-an-rss-feed-using-the-latest-features-of-hippo/</link>
		<comments>http://www.gridshore.nl/2011/12/13/creating-an-rss-feed-using-the-latest-features-of-hippo/#comments</comments>
		<pubDate>Tue, 13 Dec 2011 15:36:57 +0000</pubDate>
		<dc:creator>jettro</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[server technology]]></category>
		<category><![CDATA[hippo]]></category>
		<category><![CDATA[rome]]></category>

		<guid isPermaLink="false">http://www.gridshore.nl/?p=1216</guid>
		<description><![CDATA[<p>On my employers blog I wrote a piece about a new feature of Hippo called pipelines that can be used to create new content channels. We have created an rss feed using the standard components of Hippo combined with the Rome project. If you are interested you can read the blog post here:</p> <p>http://blog.dutchworks.nl/2011/12/13/embedding-rss-in-hippo-using-the-pipelines-feature/</p> ]]></description>
			<content:encoded><![CDATA[<p>On my employers blog I wrote a piece about a new feature of Hippo called pipelines that can be used to create new content channels. We have created an rss feed using the standard components of Hippo combined with the Rome project. If you are interested you can read the blog post here:</p>
<p><a href="http://blog.dutchworks.nl/2011/12/13/embedding-rss-in-hippo-using-the-pipelines-feature/">http://blog.dutchworks.nl/2011/12/13/embedding-rss-in-hippo-using-the-pipelines-feature/</a></p>
<div class='dd_post_share'><div class='dd_buttons'><div class='dd_button'><iframe src='http://widgets.dzone.com/links/widgets/zoneit.html?url=http%3A%2F%2Fwww.gridshore.nl%2F2011%2F12%2F13%2Fcreating-an-rss-feed-using-the-latest-features-of-hippo%2F&amp;title=Creating%20an%20rss%20feed%20using%20the%20latest%20features%20of%20Hippo&amp;t=2' height='25' width='155' frameborder='0' scrolling='no'></iframe></div></div><div style='clear:both'></div></div><!-- Social Buttons Generated by Digg Digg plugin v4.5.3.4, 
    Author : Yong Mook Kim
    Website : http://www.diggdigg2u.com -->]]></content:encoded>
			<wfw:commentRss>http://www.gridshore.nl/2011/12/13/creating-an-rss-feed-using-the-latest-features-of-hippo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hippo cms workflow with events</title>
		<link>http://www.gridshore.nl/2009/03/13/hippo-cms-workflow-with-events/</link>
		<comments>http://www.gridshore.nl/2009/03/13/hippo-cms-workflow-with-events/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 14:15:41 +0000</pubDate>
		<dc:creator>jettro</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[hippo]]></category>

		<guid isPermaLink="false">http://www.gridshore.nl/?p=670</guid>
		<description><![CDATA[<p>Hippo is an opensource content management system. Hippo has created a cms on top of the Jackrabbit repository. Hippo is not the only cms that does this trick, but it is a big one. With version 7 out there, you can now use some nice features that they have created. This post discusses one [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.gridshore.nl/wp-content/uploads/hippoworkflowevents-small.png" alt="HippoWorkflowEvents-small.png" border="0" width="150" height="117" align="left" />Hippo is an opensource content management system. <a href="http://www.onehippo.org/">Hippo</a> has created a cms on top of the Jackrabbit repository. Hippo is not the only cms that does this trick, but it is a big one. With version 7 out there, you can now use some nice features that they have created. This post discusses one of these features in detail, <strong>Workflow</strong>. I&#8217;ll explain what it is, what is can be used for and how you can extend it with business events.</p>
<p>I do want to stress that this is an idea I have about how this can be implemented. I did try it out, but do not consider this as a best practise (yet). See it as inspiration to your own extensions and maybe Hippo will contain something like this in the future.</p>
<p>The idea behind this post came from talks with Allard and Jeroen Reijn, who will write a blog post about a specific part of the solution as I will describe in the post later on.</p>
<p><span id="more-670"></span><br />
<h2>The problem</h2>
<p>Let me start by describing the reason why I wanted a solution like this. For a project we are doing, we want the content of the repository to be available in a <a href="http://lucene.apache.org/solr/">Solr</a> instance. Yes I know Hippo comes with Lucene out of the box, but we have have chosen to use solr. The reason behind this is not important for the scope of this blog post. Because of this we need to have information about content in the repository. Of course there are multiple mechanisms available to do this. I have blogged before about repository listeners. There is a big disadvantage with these listeners, they are not part of the repository. They are part of a client that connect to the repository. These listeners are also very low level, they respond to nodes being added or changed. We are more interested in the business events that take place. An example would be the publication of a document. We want to integrate with the workflow in the cms/repository.</p>
<p><a href="http://blog.jeroenreijn.com/2009/03/using-daemon-modules-with-hippo-cms-7.html">Jeroen showed me a way</a> this could be done with hippo 7 using a Daemon module.</p>
<h2>The design</h2>
<p>The following image gives an overview of the design for the solution.</p>
<p><img src="http://www.gridshore.nl/wp-content/uploads/hippoworkflowevents1.png" alt="HippoWorkflowEvents.png" border="0" width="611" height="443" /></p>
<p>Let&#8217;s start with the WorkflowEventDaemon, this is a class that get&#8217;s instantiated by hippo during initialization of the repository. This daemon queries the repository for nodes of type <em>cust:workflowevent</em>. These nodes contain a reference to the implemented EventListeners. The daemon uses these nodes to register event listeners with the EventManager. Next up are the workflow implementations. Currently the provided workflows do not raise events. Luckily it is fairly easy to extend these workflows so they do create the events. The workflow implementations use EventDispatcher instances to actually send an event to the EventManager. Using these events, the EventManager will call the listeners.</p>
<p>That is the basic idea about the solution, let&#8217;s focus on the implementation now.</p>
<h2>The implementation</h2>
<h3>Node type defintion</h3>
<p>First we need to tell the repository about the new type. This is done using CND file. The file looks like this.</p>
<pre class="brush: plain; title: ; notranslate">
&lt;'cust'='http://www.gridshore.nl/cust/1.0'&gt;
&lt;'hippostd'='http://www.hippoecm.org/hippostd/nt/1.2'&gt;
&lt;'hippo'='http://www.hippoecm.org/nt/1.2'&gt;
[cust:workflowevent]
- cust:class (String)
</pre>
<p>Hippo has created a mechanism to load nodes into the repository during startup. If you provide a file with the name <em>hippoecm-extension.xml</em>, hippo picks it up and puts these nodes in the repository. To load the CND file we add the following configuration</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;sv:node xmlns:sv=&quot;http://www.jcp.org/jcr/sv/1.0&quot; sv:name=&quot;hippo:initialize&quot;&gt;
    &lt;sv:property sv:name=&quot;jcr:primaryType&quot; sv:type=&quot;Name&quot;&gt;
        &lt;sv:value&gt;hippo:initializefolder&lt;/sv:value&gt;
    &lt;/sv:property&gt;

    &lt;sv:node sv:name=&quot;cust&quot;&gt;
        &lt;sv:property sv:name=&quot;jcr:primaryType&quot; sv:type=&quot;Name&quot;&gt;
            &lt;sv:value&gt;hippo:initializeitem&lt;/sv:value&gt;
        &lt;/sv:property&gt;
        &lt;sv:property sv:name=&quot;hippo:sequence&quot; sv:type=&quot;Double&quot;&gt;
            &lt;sv:value&gt;10009&lt;/sv:value&gt;
        &lt;/sv:property&gt;
        &lt;sv:property sv:name=&quot;hippo:namespace&quot; sv:type=&quot;String&quot;&gt;
            &lt;sv:value&gt;http://www.gridshore.nl/cust/1.0&lt;/sv:value&gt;
        &lt;/sv:property&gt;
        &lt;sv:property sv:name=&quot;hippo:nodetypesresource&quot; sv:type=&quot;String&quot;&gt;
            &lt;sv:value&gt;cust-types.cnd&lt;/sv:value&gt;
        &lt;/sv:property&gt;
    &lt;/sv:node&gt;
&lt;/sv:node&gt;
</pre>
<h3>WorkflowEventListener</h3>
<p>If you are interested in WorkflowEvents, you need to register a listener. Configuration of these listeners is done in the repository. We can add a node during startup. This is done by adding the following configuration to the hippo-extension.xml file.</p>
<pre class="brush: xml; title: ; notranslate">
    &lt;sv:node sv:name=&quot;content-workflowevents&quot;&gt;
        &lt;sv:property sv:name=&quot;jcr:primaryType&quot; sv:type=&quot;Name&quot;&gt;
            &lt;sv:value&gt;hippo:initializeitem&lt;/sv:value&gt;
        &lt;/sv:property&gt;
        &lt;sv:property sv:name=&quot;hippo:sequence&quot; sv:type=&quot;Double&quot;&gt;
            &lt;sv:value&gt;10500&lt;/sv:value&gt;
        &lt;/sv:property&gt;
        &lt;sv:property sv:name=&quot;hippo:contentresource&quot; sv:type=&quot;String&quot;&gt;
            &lt;sv:value&gt;workflowevents.xml&lt;/sv:value&gt;
        &lt;/sv:property&gt;
        &lt;sv:property sv:name=&quot;hippo:contentroot&quot; sv:type=&quot;String&quot;&gt;
            &lt;sv:value&gt;/content&lt;/sv:value&gt;
        &lt;/sv:property&gt;
    &lt;/sv:node&gt;
</pre>
<p>This references the workflowsevents.xml file. The following code shows this file that actually contains a node of type <em>cust:workflowevent</em> containing a reference to a very easy Logging implementation of the WorkflowEventListener interface</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;sv:node sv:name=&quot;workflowevents&quot; xmlns:sv=&quot;http://www.jcp.org/jcr/sv/1.0&quot;&gt;
    &lt;sv:property sv:name=&quot;jcr:primaryType&quot; sv:type=&quot;Name&quot;&gt;
        &lt;sv:value&gt;hippostd:folder&lt;/sv:value&gt;
    &lt;/sv:property&gt;
    &lt;sv:property sv:name=&quot;jcr:mixinTypes&quot; sv:type=&quot;Name&quot;&gt;
        &lt;sv:value&gt;hippo:harddocument&lt;/sv:value&gt;
    &lt;/sv:property&gt;

    &lt;sv:node sv:name=&quot;Logging Listener&quot;&gt;
        &lt;sv:property sv:name=&quot;jcr:primaryType&quot; sv:type=&quot;Name&quot;&gt;
            &lt;sv:value&gt;cust:workflowevent&lt;/sv:value&gt;
        &lt;/sv:property&gt;
        &lt;sv:property sv:name=&quot;cust:class&quot; sv:type=&quot;String&quot;&gt;
            &lt;sv:value&gt;nl.gridshore.addons.events.impl.LoggerWorkflowEventListener&lt;/sv:value&gt;
        &lt;/sv:property&gt;
    &lt;/sv:node&gt;
&lt;/sv:node&gt;
</pre>
<p>Now we have the nodes in the repository that daemon queries for. So let&#8217;s have a look at the daemon.</p>
<h3>The daemon</h3>
<p>Now we have come to the part where Jeroen helped me out. It turns out that hippo looks on it&#8217;s classpath for all MANIFEST.MF files. If such a file contains an entry for the property <strong>Hippo-Modules</strong>, hippo expects a space delimited number of classes that are implementations of the <strong>DeamonModule</strong> interface. If you are using maven, this is very easy to accomplish using the jar plugin.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;plugin&gt;
    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
    &lt;artifactId&gt;maven-jar-plugin&lt;/artifactId&gt;
    &lt;configuration&gt;
        &lt;archive&gt;
            &lt;manifestEntries&gt;
                &lt;Hippo-Modules&gt;nl.gridshore.hippo.addons.deamon.WorkflowEventDeamon&lt;/Hippo-Modules&gt;
            &lt;/manifestEntries&gt;
        &lt;/archive&gt;
    &lt;/configuration&gt;
&lt;/plugin&gt;
</pre>
<p>The daemon itself contains three parts</p>
<ul>
<li>Query the repository for registered WorkflowEventListeners</li>
<li>Instantiate each listener using reflection</li>
<li>Register each listener with the EventManager</li>
</ul>
<p>The following code block shows the complete implementation of the daemon. I hope the code is clear enough.</p>
<pre class="brush: java; title: ; notranslate">
public class WorkflowEventDeamon implements DaemonModule {
    private Session session;

    public void initialize(Session session) throws RepositoryException {
        this.session = session;

        NodeIterator nodes = obtainRegisteredWorkflowEventListeners(session);
        while (nodes.hasNext()) {
            Node node = nodes.nextNode();
            Property property = node.getProperty(&quot;cust:class&quot;);

            WorkflowEventListener listener = constructListener(property.getString());
            if (listener != null) {
                EventManager.getInstance().addWorkflowEventListener(listener);
            }
        }
    }

    private NodeIterator obtainRegisteredWorkflowEventListeners(Session session) throws RepositoryException {
        QueryManager queryManager = session.getWorkspace().getQueryManager();
        Query query = queryManager.createQuery(&quot;select * from cust:workflowevent&quot;, Query.SQL);
        QueryResult queryResult = query.execute();
        return queryResult.getNodes();
    }

    private WorkflowEventListener constructListener(String className) {
        WorkflowEventListener listener = null;
        try {
            Class clazz = this.getClass().getClassLoader().loadClass(className);
            listener = (WorkflowEventListener) clazz.getConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            logger.error(&quot;FATAL error when loading listener class : class not found&quot;,e);
        } catch (NoSuchMethodException e) {
            logger.error(&quot;FATAL error when loading listener class : no such method&quot;,e);
        } catch (IllegalAccessException e) {
            logger.error(&quot;FATAL error when loading listener class : illegal access&quot;,e);
        } catch (InvocationTargetException e) {
            logger.error(&quot;FATAL error when loading listener class : invocation target&quot;,e);
        } catch (InstantiationException e) {
            logger.error(&quot;FATAL error when loading listener class : instantiation&quot;,e);
        }
        return listener;
    }

    public void shutdown() {
        session.logout();
    }
}
</pre>
<h3>The EventManager</h3>
<p>The implementation of the EventManager is pretty straightforward. It contains a method to register listeners and a method to add an event. The following code block shows the implementation.</p>
<pre class="brush: java; title: ; notranslate">
public class EventManager {
    private final static EventManager eventManager = new EventManager();
    private final Set&lt;WorkflowEventListener&gt; eventListeners = Collections.synchronizedSet(new HashSet&lt;WorkflowEventListener&gt;());

    private EventManager() {}

    public void addEvent(WorkflowEvent workflowEvent) {
        for (WorkflowEventListener workflowEventListener : eventListeners) {
            workflowEventListener.handleEvent(workflowEvent);
        }
    }

    public void addWorkflowEventListener(WorkflowEventListener workflowEventListener) {
        eventListeners.add(workflowEventListener);
    }

    public static EventManager getInstance() {
        return eventManager;
    }
}
</pre>
<h3>Dispatching events</h3>
<p>I already mentioned I want to dispatch events from workflow components. It is a bit out of scope of this blog item to discuss workflows in Hippo very detailed. To be honest, I would not be the right person to do that. Still I want to give you a very short introduction.</p>
<p>The default workflow for promoting content from draft into publication is the <strong>Reviewed actions workflow</strong>. This workflow is provided in the default installation. Workflow items in here define what needs to happen when an author opens a document in edit mode or when an editor can do. These kind of workflow items are initiated by the frontend plugins. These plugins are wicket components that put a save and cancel button on the screen. In this blog item I&#8217;ll describe the way to extend such a workflow and how to configure the repository/cms to use our custom workflow item.</p>
<p>Let&#8217;s start with the custom workflow item</p>
<pre class="brush: java; title: ; notranslate">
public class CustomBasicReviewedActionsWorkflowImpl extends BasicReviewedActionsWorkflowImpl
        implements BasicReviewedActionsWorkflow {
    public CustomBasicReviewedActionsWorkflowImpl() throws RemoteException {
        super();
    }

    public void publish(Date date) throws WorkflowException, MappingException, RepositoryException, RemoteException {
        super.publish(date);
        EventManager.getInstance().addEvent(new WorkflowEvent(&quot;This is my first workflow event from the publish&quot;));
    }

    public void commitEditableInstance() throws WorkflowException {
        super.commitEditableInstance();
        EventManager.getInstance().addEvent(new WorkflowEvent(&quot;This is my first workflow event from the commit editable instance&quot;));
    }
}
</pre>
<p>The workflow items are configured in the repository in the following path<br/><em>/hippo:configuration/hippo:workflows/</em>. For the specific BasicReviewedActionsWorkflow we need to change two locations. In the following two locations we need to change the property <strong>hippo:classname</strong>:</p>
<ul>
<li>/hippo:configuration/hippo:workflows/default/authorreviewedactions</li>
<li>/hippo:configuration/hippo:workflows/editing/reviewedactions</li>
</ul>
<p>There is one thing left to do, hippo uses jpox to enrich the worklfow. This enriching needs to be done using the jpox maven plugin. The following code block gives an example:</p>
<pre class="brush: xml; title: ; notranslate">
            &lt;plugin&gt;
                &lt;groupId&gt;jpox&lt;/groupId&gt;
                &lt;artifactId&gt;jpox-maven-plugin&lt;/artifactId&gt;
                &lt;version&gt;1.2.0-beta-2&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;verbose&gt;false&lt;/verbose&gt;
                &lt;/configuration&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;phase&gt;compile&lt;/phase&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;enhance&lt;/goal&gt;
                        &lt;/goals&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
            &lt;/plugin&gt;
</pre>
<p>That is about it, if you fire up your repository and cms, and you change the properties as mentioned above, the workflow items should be sending events when someone saves and closes a document.</p>
<p>Hope this helped in you exploration of hippo workflows.</p>
<h2>References</h2>
<ul>
<li>http://www.onehippo.org/cms7//delve_into/custom/reference/repository/workflow.html</li>
<li><a href="http://blog.jeroenreijn.com/2009/03/using-daemon-modules-with-hippo-cms-7.html">Blog Jeroen for more information about the DaemonModule</a></li>
</ul>
<div class='dd_post_share'><div class='dd_buttons'><div class='dd_button'><iframe src='http://widgets.dzone.com/links/widgets/zoneit.html?url=http%3A%2F%2Fwww.gridshore.nl%2F2009%2F03%2F13%2Fhippo-cms-workflow-with-events%2F&amp;title=Hippo%20cms%20workflow%20with%20events&amp;t=2' height='25' width='155' frameborder='0' scrolling='no'></iframe></div></div><div style='clear:both'></div></div><!-- Social Buttons Generated by Digg Digg plugin v4.5.3.4, 
    Author : Yong Mook Kim
    Website : http://www.diggdigg2u.com -->]]></content:encoded>
			<wfw:commentRss>http://www.gridshore.nl/2009/03/13/hippo-cms-workflow-with-events/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Connecting to Hippo ecm using a springframework connector</title>
		<link>http://www.gridshore.nl/2009/01/16/connecting-to-hippo-ecm-using-a-springframework-connector/</link>
		<comments>http://www.gridshore.nl/2009/01/16/connecting-to-hippo-ecm-using-a-springframework-connector/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 13:50:18 +0000</pubDate>
		<dc:creator>jettro</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[circuit breaker]]></category>
		<category><![CDATA[hippo]]></category>
		<category><![CDATA[spring framework]]></category>

		<guid isPermaLink="false">http://www.gridshore.nl/?p=626</guid>
		<description><![CDATA[<p>Since my last article about springframework and hippo &#8220;Roadtrip from springframework to hippo 7&#8221; I have made a lot of changes to the code and moved my project to the hippo forge. With this post I want to explain what I have changed and in some situations why. I will not repeat the stuff [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.gridshore.nl/wp-content/uploads/hippo-logo.gif" alt="hippo_logo.gif" border="0" width="56" height="46" align="left" />Since my last article about springframework and hippo &#8220;<a href="http://www.gridshore.nl/2008/12/04/roadtrip-from-springframework-to-hippo-7/">Roadtrip from springframework to hippo 7</a>&#8221; I have made a lot of changes to the code and moved my project to <a href="http://forge.onehippo.org/projects/soap-exposure/">the hippo forge</a>. With this post I want to explain what I have changed and in some situations why. I will not repeat the stuff I already talked about in the <a href="http://www.gridshore.nl/2008/12/04/roadtrip-from-springframework-to-hippo-7/">previous post</a>. One of the biggest areas I made changes in, is the stability of the solution. I used the Circuit Breaker implementation as discussed by Allard in his post &#8220;<a href="http://www.gridshore.nl/2008/10/30/bring-some-stability-to-your-architecture/">Bring some stability to your architecture</a>&#8220;. Stability comes with reconnect options and a component that guards the repository. In case of to many errors the connections are closed and after a certain cool down period, new connections are created.
</p>
<p>One remark I like to make is about the connection pool. This pool is probably not production ready. I did not do any performance tests and it is a bit rough around the edges.</p>
<p>That said, let&#8217;s move on and start talking about the solution.</p>
<p><span id="more-626"></span><br />
<h2>Overview</h2>
<p>Let&#8217;s start of with an overview of the problem domain. You have a running <a href="http://docs.onehippo.org/">hippo repository</a>, you can use the cms to edit content, the console to configure the details, the site toolkit to create a site and maven to bundle it all together. Now you have a website (maybe an existing, maybe a new one) that needs to serve content from the repository. Or you want to expose the content using an rss feed, or maybe even a web service. The <a href="http://forge.onehippo.org/projects/soap-exposure/">sample application</a> that you can find on the forge of hippo uses a web service to demonstrate the capabilities.</p>
<p>To be able to connect and interact with the hippo repository (over rmi), you need two jar files: hippo-ecm-api.jar and hippo-ecm-repository-connector.jar. Using these jars and a bit of spring wiring, You can create a wrapper layer around the Hippo repository connection.</p>
<p>The following image shows the classes we need for interacting with the repository. The SessionFactory uses the class <code>org.hippoecm.repository.HippoRepositoryFactory</code> to get a reference to the hippo repository. With this reference new sessions can be created. So that&#8217;s it? No not really. For performance reasons we want to reuse session when they are only used for read only actions. We also want to recover from connection problems and we want a mechanism to listen for specific events in the repository.</p>
<div style="text-align:center;"><img src="http://www.gridshore.nl/wp-content/uploads/overview-hippo-spring-connection.png" alt="overview-hippo-spring-connection.png" border="0" width="575" height="440" /></div>
<h2>Session pooling</h2>
<p>To be able to do more with sessions, we wrap the standard <code>javax.jcr.Session</code>. The interface we expose is different than the standard session. This enables us to create a common interface for normal obtained sessions and pooled sessions. An important method for pooled sessions is the close method. For normal sessions, this means logout, for pooled sessions this means return to the pool.</p>
<p>Obtaining a session from the pool is done via the <code>DefaultHippoSessionPool</code> using the interface <code>HippoSessionPool</code>. To be able to initialize the pool and to clean it, two methods are exposed as well. This enables you to re-initialize the pool when for instance the connection was broken.</p>
<h2>Listening to the repository</h2>
<p>When creating an external application it might be interesting to know what happens in the repository. That is why the event listener is available. The <code>SessionListenerService</code> accepts <code>RepoEventListener</code> objects and notifies them of events taking place in the repository. The service uses a session to register the listeners. Do remember that the listeners are registered over an rmi connection. If the connection dies, the listeners will not receive events.</p>
<h2>Session Manager</h2>
<p>In order to handle broken connections, starting up pools, re-registering listeners and provide an easy interface to obtain read-only as well as normal sessions, we have the <code>SessionManager</code>. The SessionManager initializes the pool and registeres the listeners. It also closes the pool and tries to de-register listeners when closing down or in case of problems.</p>
<p>The SessionManager is the class used by your code to access the repository. An example is the <code>BaseQueryTemplateAdapter</code> that uses the SessionManager to easily query the repository for a search string.</p>
<h2>CircuitBreaker</h2>
<p>We already talked about broken connections, re-initializing the pool, re-registering the listners. How do we know the connection is broken? This is less obvious than you expect. Especially for the listeners. A session can be checked for liveness, but the listeners are not in a normal synchronous process. The listeners are also not notified of broken connections. Therefore we have introduced the circuit breaker that takes away part of the pain. The following image gives you an overview of the circuit breaker implementation. If you want to read more about the circuit breaker in general, read the <a href="http://www.gridshore.nl/2008/10/30/bring-some-stability-to-your-architecture/">post from Allard</a>.</p>
<div style="text-align:center;"><img src="http://www.gridshore.nl/wp-content/uploads/circuitbreaker-hippo-connection.png" alt="circuitbreaker-hippo-connection.png" border="0" width="465" height="506" /></div>
<p>So how does it work? The mothods in the HippoSessionFactory are annotated with the @Monitored tag. That way the aspect <code>AnnotatedMethodCircuitBreakerInterceptor</code> wraps all method calls to create a new session. If errors occur it might cause the CircuitBreaker implementation to move to OPEN state. After the cooldown period, a connection is tried again. If that connection succeeds, the state is changed to CLOSED again. All registered listeners of type <code>StateChangeListener</code> are notifed. The <code>SessionManager</code> also implements the StateChangeListener interface. That way the CircuitBreaker notifies the SessionManager when the state is changed. The SessionManager uses this information to re-initialize the session pool and re-register the listeners.</p>
<h2>Last remarks</h2>
<p>That&#8217;s it for this post. I hope it is clear how you can connect to hippo using spring by now. Hippo provides documentation on this topic itself as well. If you want to try this out, go to the hippo website below. Look for the quickstart. Run the repository and fire up the sample I have provided. For more information about the webservice, check my previous post. </p>
<h2>References</h2>
<ul>
<li><a href="http://www.gridshore.nl/2008/12/04/roadtrip-from-springframework-to-hippo-7/">http://www.gridshore.nl/2008/12/04/roadtrip-from-springframework-to-hippo-7/</a></li>
<li><a href="http://www.gridshore.nl/2008/10/30/bring-some-stability-to-your-architecture/">http://www.gridshore.nl/2008/10/30/bring-some-stability-to-your-architecture/</a></li>
<li><a href="http://docs.onehippo.org/">http://docs.onehippo.org/</a></li>
<li><a href="http://www.onehippo.org/cms7/delve_into/quickstart.html">http://www.onehippo.org/cms7/delve_into/quickstart.html</a></li>
<li><a href="http://forge.onehippo.org/projects/soap-exposure/">http://forge.onehippo.org/projects/soap-exposure/</a></li>
</ul>
<div class='dd_post_share'><div class='dd_buttons'><div class='dd_button'><iframe src='http://widgets.dzone.com/links/widgets/zoneit.html?url=http%3A%2F%2Fwww.gridshore.nl%2F2009%2F01%2F16%2Fconnecting-to-hippo-ecm-using-a-springframework-connector%2F&amp;title=Connecting%20to%20Hippo%20ecm%20using%20a%20springframework%20connector&amp;t=2' height='25' width='155' frameborder='0' scrolling='no'></iframe></div></div><div style='clear:both'></div></div><!-- Social Buttons Generated by Digg Digg plugin v4.5.3.4, 
    Author : Yong Mook Kim
    Website : http://www.diggdigg2u.com -->]]></content:encoded>
			<wfw:commentRss>http://www.gridshore.nl/2009/01/16/connecting-to-hippo-ecm-using-a-springframework-connector/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Roadtrip from springframework to Hippo 7</title>
		<link>http://www.gridshore.nl/2008/12/04/roadtrip-from-springframework-to-hippo-7/</link>
		<comments>http://www.gridshore.nl/2008/12/04/roadtrip-from-springframework-to-hippo-7/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 23:22:36 +0000</pubDate>
		<dc:creator>jettro</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[hippo]]></category>
		<category><![CDATA[soapui]]></category>
		<category><![CDATA[spring framework]]></category>
		<category><![CDATA[spring-ws]]></category>

		<guid isPermaLink="false">http://www.gridshore.nl/?p=504</guid>
		<description><![CDATA[<p>At the moment I am doing a proof of concept for a customer together with two developers from the customer and a developer from Hippo. We are using the future product of hippo, Hippo 7. It is a nice technology stack using JackRabbit for the content repository and wicket as a view technology for [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.gridshore.nl/wp-content/uploads/hippo-logo.gif" alt="hippo_logo.gif" border="0" width="56" height="46" align="left" /><img src="http://www.gridshore.nl/wp-content/uploads/springlogo.png" alt="springlogo.png" border="0" width="100" height="45" align="right" />At the moment I am doing a proof of concept for a customer together with two developers from the customer and a developer from <a href="http://www.onehippo.com">Hippo</a>. We are using the future product of hippo, Hippo 7. It is a nice technology stack using <a href="http://jackrabbit.apache.org/">JackRabbit</a> for the content repository and wicket as a view technology for the cms. The guys from Hippo are working very hard to come up with the first release of Hippo 7. This release has been rebuild from the ground up. One of the requirements for the project is a webservice that accesses the hippo repository and returns some information from the repository. That is what this post is about.</p>
<p>This post will talk about connecting to the hippo repository using the spring framework. I&#8217;ll show a very basic (not production ready) connection pooling into the repository. Using this connection, the spring webservices project will step in and take over. Using spring-ws I am exposing a search into the documents.</p>
<p>Feel free to post a comment if you have questions, the sources are again available on <a href="http://code.google.com/p/gridshore">google code</a>.</p>
<p><span id="more-504"></span>
<p>I want to start with some references to the frameworks that I have used. That way you can try to follow along.</p>
<ol>
<li><a href="http://docs.onehippo.org/cms7/delve_into/quickstart.html">Hippo ecm quickstart</a> &#8211; easy access to start your own hippo repository. If you are having problems starting the application, check the start script and remove the -Xms stuff at the end of the file somewhere.</li>
<li><a href="http://maven.apache.org/">Apache maven</a> &#8211; Used to build the sample</li>
<li><a href="http://code.google.com/p/gridshore/source/checkout">source code</a> &#8211; The source code for the complete project.</li>
<li><a href="http://www.jetbrains.com/idea/download/index.html#mac">IntelliJ</a> &#8211; You might try another IDE, but I cannot make any guarantees.</li>
<li><a href="http://www.soapui.org/">SoapUI</a> &#8211; Nice tool for testing the webservice, but any webservice client should be able to access the wsdl and use it.</li>
</ol>
<p>Let&#8217;s start with the basics, I think you were able to get the hippo quickstart running. I am not going into details in that area, check the <a href="http://docs.onehippo.org/">hippo documentation</a> which is becoming very useful. Now that you have a running repository, you want to connect to it. Startup your favorite IDE (oke, no jokes anymore) and create a very difficult class with code as shown in the following piece of code.</p>
<pre class="brush: java; title: ; notranslate">
String location = &quot;rmi://localhost:1099/hipporepository&quot;;
HippoRepositoryFactory.setDefaultRepository(location);
HippoRepository repo = HippoRepositoryFactory.getHippoRepository();
Session session = repo.login(&quot;admin&quot;, &quot;admin&quot;.toCharArray());
Workspace workspace = session.getWorkspace();
Query query = queryManager.createQuery(
	&quot;//element(*,defaultcontent:article)[jcr:like(@defaultcontent:title,'%title%')]&quot;, Query.XPATH);
QueryResult queryResult = query.execute();
NodeIterator nodes = queryResult.getNodes();
while (nodes.hasNext()) {
    Node node = nodes.nextNode();
    System.out.println(&quot;title : &quot; + node.getProperty(&quot;defaultcontent:title&quot;));
}
session.close();
</pre>
<p>Problem is that you need a lot of dependencies to do this. You can look up the right document on the hippo website and download all the jars, you can also follow along and build it in a slightly more sturctured way. But in the end, this is all there is to it. First you get a reference to the Hippo repository, than you create a session by a executing a login. From the session you ask the workspace and the query manager. The querymanager is used to execute a query that looks for all documents of type <em>defaultcontent:article</em> with a title containing the word <em>title</em>. Then we use the QueryResult to print the actual titles from all found articles.</p>
<p>Now that we know how to connect to Hippo, we are going to use this knowledge to make it useable in the springframework world. The following image shows the interfaces and classes that we need to obtain a session.</p>
<div style="text-align:center;"><img src="http://www.gridshore.nl/wp-content/uploads/overviewhippoconnection.png" alt="OverviewHippoConnection.png" border="0" width="470" height="320" /></div>
<p>The image shows the blue HippoRepositoryFactory, blue means a gridshore class. This is a spring <strong>FactoryBean</strong> that creates an implementation of the HippoRepository, the orange ones are from Hippo. It uses the orange HippoRepositoryFactory to actually create the HippoRepository instance. Just like in the first code block I showed. The following code block shows the implementation of this class. The other blue item is the HippoSessionFactory. Implementations of this interface create sessions represented by the green color coming from the original JackRabbit libraries. We&#8217;ll discuss this class after the code block.</p>
<pre class="brush: java; title: ; notranslate">
public class HippoRepositoryFactory implements FactoryBean, InitializingBean {
    private String location = &quot;rmi://localhost:1099/hipporepository&quot;; 

    public HippoRepositoryFactory() {
    }

    public HippoRepositoryFactory(String location) {
        if (null != location &amp;&amp; !&quot;&quot;.equals(location)) {
            this.location = location;
        }
    }

    public Object getObject() throws Exception {
        return org.hippoecm.repository.HippoRepositoryFactory.getHippoRepository();
    }

    public Class getObjectType() {
        return HippoRepository.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public void afterPropertiesSet() throws Exception {
        org.hippoecm.repository.HippoRepositoryFactory.setDefaultRepository(location);
    }
}
</pre>
<p>The code block shows you we initialize the HippoRepositoryFactory wit the default location. We also need to implement the methods <em>getObject()</em> and <em>getObjectType</em>. This kind of classes can be used immediately in the spring configuration. The following code block shows part of this configuration in spring for the mentioned objects.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;&gt;
    &lt;!-- loads the propety file from the classpath with some configuration parameters
         default file is loaded from the jar file. Place your on version ealier on the classpath.
     --&gt;
    &lt;bean id=&quot;jcrConfig&quot; class=&quot;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&quot;&gt;
        &lt;property name=&quot;location&quot; value=&quot;classpath:/jcrconfig.properties&quot;/&gt;
        &lt;property name=&quot;placeholderPrefix&quot; value=&quot;$jcr{&quot;/&gt;
    &lt;/bean&gt;
    &lt;!-- Special spring factory bean to create a HippoRepository instance --&gt;
    &lt;bean id=&quot;hippoRepositoryFactory&quot; class=&quot;nl.gridshore.samples.hippo.impl.HippoRepositoryFactory&quot;&gt;
        &lt;!-- Since we use the default the following is optional --&gt;
        &lt;constructor-arg index=&quot;0&quot; value=&quot;$jcr{jcr.rmi.connection.url}&quot;/&gt;
    &lt;/bean&gt;
    &lt;!-- Factory bean used to create new Sessions for the hippo repository --&gt;
    &lt;bean id=&quot;sessionFactory&quot; class=&quot;nl.gridshore.samples.hippo.impl.HippoSessionFactoryImpl&quot;&gt;
        &lt;property name=&quot;hippoRepository&quot; ref=&quot;hippoRepositoryFactory&quot;/&gt;
        &lt;!-- following parameters are optional --&gt;
        &lt;property name=&quot;defaultUsername&quot; value=&quot;$jcr{jcr.username}&quot;/&gt;
        &lt;property name=&quot;defaultPassword&quot; value=&quot;$jcr{jcr.password}&quot;/&gt;
    &lt;/bean&gt;
&lt;/beans&gt;
</pre>
<p>Now it is possible to create a client that uses the spring configuration to make a call to the hippo repository. Actually the following piece of code shows what you can do right now.</p>
<pre class="brush: java; title: ; notranslate">
public class ReadRepository {
    public static void main(String[] args) throws RepositoryException {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{&quot;connector-config.xml&quot;});

        RepoSessionTemplate repoSessionTemplate = (RepoSessionTemplate) ctx.getBean(&quot;sessionTemplate&quot;);
        readNodes(repoSessionTemplate);
    }

    private static void readNodes(RepoSessionTemplate repoSessionTemplate) throws RepositoryException {
        QueryResult queryResult;

        queryResult = repoSessionTemplate.readFromSession(new SessionCallback() {
            public QueryResult readFromSession(QueryManager queryManager) throws RepositoryException {
                Query query = queryManager.createQuery(
                        &quot;//element(*,defaultcontent:article)[jcr:like(@defaultcontent:title,'%title%')]&quot;, Query.XPATH);
                return query.execute();
            }
        });
        NodeIterator nodes = queryResult.getNodes();
        while (nodes.hasNext()) {
            Node node = nodes.nextNode();
            System.out.println(&quot;Node title : &quot; + node.getName());
        }
    }
}
</pre>
<p>The result when you run this class, if you have your repository running, will be:<br/></p>
<p>
Node title : myarticle1<br/><br />
Node title : hippo:prototype<br/><br />
Node title : myarticle1<br/><br />
Node title : myarticle2<br/>
</p>
<p>
Oke I have to admit, I cheat. There are more classes used in this sample. But before I&#8217;ll go into these classes, I want to explain some very basic things of hippo, or using JackRabbit in general.</p>
<p>The entry point for doing something with a repository is the Session. Creating a session object is not a cheap operation. Therefore it is advisable to reuse created sessions when only reading data. Websites with a lot of traffic will find great performance increases when using a Session pool. To help people not to close session that need to be pooled, I have created a class hierarchy around the sessions and a session pool object. Another class I have created is the <em>RepoSessionTemplate</em>. This is a very common approach in the springframework world. It prevents you from having to write to much boiler plate code. The following image shows the relationships between the different classes.</p>
<div style="text-align:center;"><img src="http://www.gridshore.nl/wp-content/uploads/overviewhipposessionpooling.png" alt="OverviewHippoSessionPooling.png" border="0" width="541" height="369" /></div>
<p>The image might be a bit overwhelming. I suggest you download the code and have a look at it. I think it is not really hard. There is a RepoSession interface that defines the methods that our clients might need when using a session. The WrappedSession represents a RepoSession that contains a wrapped repository session. The PooledSession is a special WrappedSession, it is not closed when you call the close() method. Instead it returns the session back to the pool. Now I want to have a look at the RepoSessionTemplate and it&#8217;s concrete implementation. This interface has two methods, one with username/password and one without. By providing a username, you will not get a pooled session. By omitting a username, you do get a pooled connection. No matter which path you choose to go, the template adapter will follow the same road, accept for creating the RepoSession. In the first situation it is created in the Template adapter itself using the session factory, in the other situation, the template makes use of the pool to obtain a RepoSession. Let&#8217;s have a look at the template adapter code.</p>
<pre class="brush: java; title: ; notranslate">
    public QueryResult readFromSession(SessionCallback sessionCallback) throws RepositoryException {
        logger.debug(&quot;Read from session is called without username&quot;);
        RepoSession session = hippoSessionPool.obtainSession();
        return doReadFromSession(sessionCallback, session);
    }

    protected QueryResult doReadFromSession(SessionCallback sessionCallback, RepoSession session) throws RepositoryException {
        logger.debug(&quot;Execute the callback and close the session afterwards&quot;);
        QueryResult queryResult;
        try {
            Workspace workspace = session.getWorkspace();
            queryResult = sessionCallback.readFromSession(workspace.getQueryManager());
        } finally {
            session.close();
        }
        return queryResult;
    }
</pre>
<p>The structure is the same as the first code block I showed. In another code block you already saw the SessionCallback at work. I&#8217;ll repeat it in one of the following blocks of code when discussing the webservice part. Actually it is not a bad moment to start talking about that part of the application. We now have access to a mechanism to fire queries at the repository. Let&#8217;s use that to obtain a search parameter from a webservice request and return the found documents in a response.</p>
<p>So what do we need to create a webservice, well a guide to help us would be nice. Well you have multiple options. One is a blogpost I wrote quite some time a go: <a href="http://www.gridshore.nl/blog/index.php?/archives/66-Using-Spring-ws-for-creating-a-webservice.html">using spring-ws to create a webservice</a> or the <a href="http://static.springsource.org/spring-ws/sites/1.5/reference/html/server.html">reference documentation</a>. For the sample I used the reference manual, especially for the JDom part. Since it has been written down so well and I have the source code for you available, I will not go into the configuration of the webservice stuff. Check the file <a href="http://code.google.com/p/gridshore/source/browse/trunk/springconnector/webservice/src/main/resources/spring-servlet.xml">spring-servlet.xml</a> and the xsd <a href="http://code.google.com/p/gridshore/source/browse/trunk/springconnector/webservice/src/main/webapp/document.xsd">document.xsd</a>. Instead of all that, let&#8217;s focus on the endpoint. The endpoint is used for analyzing the request as well as creating the response. I have chosen a payload endpoint, no need for all the soap specifics, I only want the actual content. Reading from the request is done using XPath expressions. Creating the response is done with JDom. The following piece of code shows you the first part of the class with request handling in it.</p>
<pre class="brush: java; title: ; notranslate">
public class SearchNewsEndpoint extends AbstractJDomPayloadEndpoint {
    private static Logger logger = LoggerFactory.getLogger(SearchNewsEndpoint.class);

    private RepoSessionTemplate repoSessionTemplate;

    private XPath searchTextExpression;
    private Namespace namespace;

    public SearchNewsEndpoint() {
        namespace = Namespace.getNamespace(&quot;grid&quot;, &quot;http://gridshore.nl/schemas&quot;);
        try {
            searchTextExpression = XPath.newInstance(&quot;//grid:SearchText&quot;);
            searchTextExpression.addNamespace(namespace);
        } catch (JDOMException e) {
            logger.error(&quot;Problem while creating an XPath&quot;);
            throw new EndpointConfigurationException(&quot;Problem in the SearchNewsEndpoint&quot;, e);
        }
    }

    protected Element invokeInternal(Element requestElement) throws Exception {
        final String searchText = searchTextExpression.valueOf(requestElement);
        ...
    }
}
</pre>
<p>In the code you see that I use the JDomPayload endpoint. I first create a namespace and using that namespace an XPath. By reading the xsd, you can see that the SearchRequest element must contain an element SearchText. This element contains the actual string that we use in the search. The <em>searchTextExpression</em> now contain the expression that we can use when a request comes in. The method <em>invokeInternal</em> is called when a request comes in and as you can see I obtain the value of the SearchText element and store it in  the variable searchText. The following piece of code comes instead of the &#8230; above.</p>
<pre class="brush: java; title: ; notranslate">
        Element searchResponse = new Element(&quot;SearchResponse&quot;, namespace);

        QueryResult queryResult = repoSessionTemplate.readFromSession(new SessionCallback() {
            public QueryResult readFromSession(QueryManager queryManager) throws RepositoryException {
                Query query = queryManager.createQuery(&quot;//element(*,defaultcontent:article)[jcr:like(@defaultcontent:title,'%&quot;
                        + searchText + &quot;%')]&quot;, Query.XPATH);
                return query.execute();
            }
        });
        NodeIterator nodes = queryResult.getNodes();
        while (nodes.hasNext()) {
            Node node = nodes.nextNode();
            Property title = node.getProperty(&quot;defaultcontent:title&quot;);
            Property introduction = node.getProperty(&quot;defaultcontent:introduction&quot;);
            Property body = node.getProperty(&quot;defaultcontent:body&quot;);
            Property uuid = node.getProperty(&quot;jcr:uuid&quot;);

            Element articleElement = new Element(&quot;Article&quot;, namespace);
            articleElement.setAttribute(&quot;uuid&quot;,uuid.getString());
            Element titleElement = new Element(&quot;Title&quot;, namespace);
            Element introductionElement = new Element(&quot;Introduction&quot;, namespace);
            Element bodyElement = new Element(&quot;Body&quot;, namespace);

            titleElement.setText(title.getString());
            introductionElement.setText(introduction.getString());
            bodyElement.setText(body.getString());

            articleElement.addContent(titleElement);
            articleElement.addContent(introductionElement);
            articleElement.addContent(bodyElement);
            searchResponse.addContent(articleElement);
        }

        return searchResponse;
</pre>
<p>All the Elements are JDom elements and will be transformed into a valid response. You can see the first element <em>SearchResponse</em>, which will be given multiple <em>Article</em> elements, and so on. The repoSessionTemplate is used to execute the query and in the end obtain the Nodes containing the articles with a title containing the entered text. Using the <em>getProperty</em> methods I can obtain the actual data and create a response out of it.</p>
<p>That is about it, now you can fire up your web project containing the spring-ws project. If your repository is still running you should be able to send a request and get a response. For those of you not familiar with a webservice client, I recommend using SoapUI.</p>
<p>When soapui is running, go to File > New Project. A wizzard will appear. Enter the following url into the <em>Initial wsdl/wadl</em> box.</p>
<p>http://localhost:8081/searchService/search.wsdl<br/></p>
<p>The result should be a Request 1, double click it to open. Change the value of SearchText into <em>title</em>, push the run button and you should receive the following response.</p>
<pre class="brush: java; title: ; notranslate">
&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&gt;
   &lt;SOAP-ENV:Header/&gt;
   &lt;SOAP-ENV:Body&gt;
      &lt;grid:SearchResponse xmlns:grid=&quot;http://gridshore.nl/schemas&quot;&gt;
         &lt;grid:Article uuid=&quot;118b876b-fc73-4400-89b8-5a0e2153628d&quot;&gt;
            &lt;grid:Title&gt;title published version&lt;/grid:Title&gt;
            &lt;grid:Introduction&gt;introduction&lt;/grid:Introduction&gt;
            &lt;grid:Body&gt;body&lt;/grid:Body&gt;
         &lt;/grid:Article&gt;
         &lt;grid:Article uuid=&quot;2b2c3f3c-a738-4ca6-a0d6-30eac3ca8c55&quot;&gt;
            &lt;grid:Title&gt;title&lt;/grid:Title&gt;
            &lt;grid:Introduction&gt;introduction&lt;/grid:Introduction&gt;
            &lt;grid:Body&gt;body&lt;/grid:Body&gt;
         &lt;/grid:Article&gt;
         &lt;grid:Article uuid=&quot;db1bddc5-d29f-47a1-ac12-b34d97a82715&quot;&gt;
            &lt;grid:Title&gt;title&lt;/grid:Title&gt;
            &lt;grid:Introduction&gt;introduction&lt;/grid:Introduction&gt;
            &lt;grid:Body&gt;body&lt;/grid:Body&gt;
         &lt;/grid:Article&gt;
         &lt;grid:Article uuid=&quot;b363e8be-2ec7-4f62-8ba0-2f9c7a335b17&quot;&gt;
            &lt;grid:Title&gt;title&lt;/grid:Title&gt;
            &lt;grid:Introduction&gt;introduction&lt;/grid:Introduction&gt;
            &lt;grid:Body&gt;body&lt;/grid:Body&gt;
         &lt;/grid:Article&gt;
      &lt;/grid:SearchResponse&gt;
   &lt;/SOAP-ENV:Body&gt;
&lt;/SOAP-ENV:Envelope&gt;
</pre>
<p>Wow, cool isn&#8217;t it? That is about it. Hope you liked it and can use it. Thanks to Jeroen Reijn from Hippo for helping with well euh Hippo and Allard for the thinking with me on the Sessions and pooling stuff.</p>
<div class='dd_post_share'><div class='dd_buttons'><div class='dd_button'><iframe src='http://widgets.dzone.com/links/widgets/zoneit.html?url=http%3A%2F%2Fwww.gridshore.nl%2F2008%2F12%2F04%2Froadtrip-from-springframework-to-hippo-7%2F&amp;title=Roadtrip%20from%20springframework%20to%20Hippo%207&amp;t=2' height='25' width='155' frameborder='0' scrolling='no'></iframe></div></div><div style='clear:both'></div></div><!-- Social Buttons Generated by Digg Digg plugin v4.5.3.4, 
    Author : Yong Mook Kim
    Website : http://www.diggdigg2u.com -->]]></content:encoded>
			<wfw:commentRss>http://www.gridshore.nl/2008/12/04/roadtrip-from-springframework-to-hippo-7/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Integrate hippo cms into a spring application</title>
		<link>http://www.gridshore.nl/2008/07/06/integrate-hippo-cms-into-a-spring-application/</link>
		<comments>http://www.gridshore.nl/2008/07/06/integrate-hippo-cms-into-a-spring-application/#comments</comments>
		<pubDate>Sun, 06 Jul 2008 21:48:52 +0000</pubDate>
		<dc:creator>jettro</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[hippo]]></category>
		<category><![CDATA[spring framework]]></category>

		<guid isPermaLink="false">http://www.gridshore.nl/?p=153</guid>
		<description><![CDATA[<p>This article is about integrating the hippo cms with a spring framework application. To be honest, the amount of integration is very easy if you know how to configure the api that is provided by hippo. So what are we going to do? In this article I am going to describe the high level [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.gridshore.nl/wp-content/uploads/hippo-logo.gif" alt="hippo_logo.gif" border="0" width="56" height="46" align="left"/>This article is about integrating the hippo cms with a spring framework application. To be honest, the amount of integration is very easy if you know how to configure the api that is provided by hippo. So what are we going to do? In this article I am going to describe the high level architecture of a normal spring-mvc application that makes use of the hippo api to store and obtain content from the hippo content repository.</p>
<p>For this article I have made use of the hippo 6 version. Things might change a lot when you are dealing with hippo 7. Starting release 7, hippo is fully compliant with the Java Content Repository API.</p>
<p>Continue reading if you want to learn about how to integrate hippo 6 with springframework.</p>
<p><span id="more-153"></span></p>
<p>Before jumping into the code, let&#8217;s have a look at the general architecture  of the application:</p>
<p><img src="http://www.gridshore.nl/wp-content/uploads/hippo-integration.png" alt="hippo-integration.png" border="0" width="522" height="299" /></p>
<p>There are two front end applications. You can use the hippo cms to create content and configure your repository. This is usually not a front end normal visitors will see. For Hippo 7, the cms is completely rewritten. And to be honest, they did that for a good reason. But that is not what this article is about, so that is the last thing I have said about it.</p>
<p>The other front end application is the &#8220;frontend application&#8221; <img src='http://www.gridshore.nl/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> . This is the actual spring framework application. Here you can find the base architecture for a pretty standard spring mvc application. For completeness, I&#8217;ll give you an overview for that as well.</p>
<p><img src="http://www.gridshore.nl/wp-content/uploads/hippo-integration-highleveldesign.png" alt="hippo-integration-highleveldesign.png" border="0" width="570" height="570" /></p>
<p>The design contains the usual layers: interaction (web and import), business, dao, domain and common. To completely separate the hippo stuff, I have moved them into an extra integration layer. This layer embeds the hippo api. This is also the module I&#8217;ll focus on. Next to that I will also show some samples of a HippoDao class and most of all the abstract parent for all hippo data access classes.</p>
<p>Let&#8217;s start with the integration module, there is one class that is the interface to the hippo repository. Let&#8217;s call the interface the content connector and the the actual implementation the HippoContentConnector. To be able to connect to the repository, we have the availability of the hippo api. There are some components that we need to use to connect to hippo.</p>
<ul>
<li><em>nl.hippo.client.webdav.service.WebdavServiceImpl</em> &#8211; implementation that actually does the communication with the repository using the webdav functionality.</li>
<li><em>nl.hippo.client.event.service.UpdateNotificationServiceImpl</em> &#8211; This service is used by the api to invalidate it&#8217;s cache. It gets messages via jms with information about updated repository items.</li>
<li><em>nl.hippo.client.caching.service.CachingServiceImpl</em> &#8211; As the name says, this is all about caching. It is used by the webdav service to determine if an item should be obtained from the repository or not.</li>
<li><em>nl.hippo.client.api.event.EventAwareManager</em> &#8211; The relationship between the update service and the caching service. The event manager receives the events and notifies the caching service.</li>
</ul>
<p>The following image clarifies the relations that are available and that we need to create spring beans for. A few of the beans are not yet discussed. They are used to configure the other beans. In the image all the greens beans are hippo provided classes, the yellow ones come from the project. They are just factory beans to provided the appropriate configuration.</p>
<p><img src="http://www.gridshore.nl/wp-content/uploads/onsoranje-hippospringconfig.png" alt="onsoranje-hippospringconfig.png" border="0" width="449" height="457" /></p>
<p>Next step is to have a look at the actual spring configuration:</p>
<pre class="brush: xml; title: ; notranslate">
&lt; ?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
       xsi:schemaLocation=&quot;
              http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
    &lt;bean id=&quot;connectionProps&quot; class=&quot;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&quot;&gt;
        &lt;property name=&quot;locations&quot; value=&quot;file:${config.dir}/connection.properties&quot;/&gt;
        &lt;property name=&quot;placeholderPrefix&quot; value=&quot;$con{&quot;/&gt;
    &lt;/bean&gt;
    &lt;bean id=&quot;&lt;strong&gt;contentConnector&quot; class=&quot;nl.jteam.knvb.integration.hippo.HippoContentConnector&quot;&gt;
        &lt;property name=&quot;webdavService&quot; ref=&quot;webdavService&quot;/&gt;
    &lt;/bean&gt;
    &lt;bean id=&quot;&lt;strong&gt;hippoCachingService&quot; class=&quot;nl.hippo.client.caching.service.CachingServiceImpl&quot;&gt;
        &lt;constructor -arg index=&quot;0&quot;&gt;
            &lt;bean class=&quot;nl.hippo.client.caching.JCSDefaultCache&quot;&gt;
                &lt;constructor -arg value=&quot;default&quot;/&gt;
            &lt;/bean&gt;
        &lt;/constructor&gt;
        &lt;constructor-arg index=&quot;1&quot; ref=&quot;hippoEventAwareManager&quot;/&gt;
        &lt;constructor-arg index=&quot;2&quot; value=&quot;default&quot;/&gt;
    &lt;/bean&gt;
    &lt;bean id=&quot;&lt;strong&gt;hippoEventAwareManager&quot; factory-bean=&quot;updateNotificationService&quot; factory-method=&quot;getEventAwareManager&quot;/&gt;
    &lt;/bean&gt;&lt;bean id=&quot;updateNotificationService&quot; class=&quot;nl.hippo.client.event.service.UpdateNotificationServiceImpl&quot;
          init-method=&quot;start&quot;&gt;
        &lt;constructor -arg index=&quot;0&quot; ref=&quot;updateNotificationConfigFactory&quot;/&gt;
    &lt;/bean&gt;
    &lt;bean id=&quot;&lt;strong&gt;webdavService&quot; class=&quot;nl.hippo.client.webdav.service.WebdavServiceImpl&quot;&gt;
        &lt;constructor -arg index=&quot;0&quot; ref=&quot;webdavConfig&quot;/&gt;
        &lt;constructor -arg index=&quot;1&quot; ref=&quot;hippoCachingService&quot;/&gt;
        &lt;constructor -arg index=&quot;2&quot; value=&quot;true&quot;/&gt;
    &lt;/bean&gt;
    &lt;bean id=&quot;&lt;strong&gt;webdavConfig&quot; class=&quot;nl.hippo.client.webdav.WebdavConfig&quot;&gt;
        &lt;constructor -arg index=&quot;0&quot; ref=&quot;webdavConfigFactory&quot;/&gt;
    &lt;/bean&gt;
    &lt;bean id=&quot;&lt;strong&gt;webdavConfigFactory&quot; class=&quot;nl.jteam.knvb.integration.hippo.WebdavConfigFactorybean&quot;&gt;
        &lt;property name=&quot;webdavFilesPath&quot; value=&quot;$con{webdav.filesPath}&quot;/&gt;
        &lt;property name=&quot;webdavHost&quot; value=&quot;$con{webdav.host}&quot;/&gt;
        &lt;property name=&quot;webdavNamespace&quot; value=&quot;$con{webdav.namespace}&quot;/&gt;
        &lt;property name=&quot;webdavPassword&quot; value=&quot;$con{webdav.password}&quot;/&gt;
        &lt;property name=&quot;webdavPort&quot; value=&quot;$con{webdav.port}&quot;/&gt;
        &lt;property name=&quot;webdavProtocol&quot; value=&quot;$con{webdav.protocol}&quot;/&gt;
        &lt;property name=&quot;webdavRealm&quot; value=&quot;$con{webdav.realm}&quot;/&gt;
        &lt;property name=&quot;webdavUsername&quot; value=&quot;$con{webdav.username}&quot;/&gt;
    &lt;/bean&gt;
    &lt;bean id=&quot;&lt;strong&gt;updateNotificationConfigFactory&quot;class=&quot;nl.jteam.knvb.integration.hippo.UpdateNotificationConfigFactorybean&quot;&gt;
        &lt;property name=&quot;jndiInitialContextFactory&quot; value=&quot;$con{jndi.initialContextFactory}&quot;/&gt;
        &lt;property name=&quot;jndiProviderURL&quot; value=&quot;$con{jndi.providerURL}&quot;/&gt;
        &lt;property name=&quot;jmsConnectionFactory&quot; value=&quot;$con{jms.connectionFactory}&quot;/&gt;
        &lt;property name=&quot;jmsPassword&quot; value=&quot;$con{jms.password}&quot;/&gt;
        &lt;property name=&quot;jmsUsername&quot; value=&quot;$con{jms.username}&quot;/&gt;
        &lt;property name=&quot;jmsTopic&quot; value=&quot;$con{jms.topic}&quot;/&gt;
        &lt;property name=&quot;jmsReconnectDelay&quot; value=&quot;$con{jms.reconnectDelay}&quot;/&gt;
    &lt;/bean&gt;
&lt;/beans&gt;
</pre>
<p>You can see from the config we make use of factory beans (webdavConfigFactory) and factory methods (hippoEventAwareManager). That is the most important part of the spring configuration. We now have a fully configured ContentConnector that knows how to do stuff with the hippo repository. Some of the methods that are implemented are the following:</p>
<pre class="brush: java; title: ; notranslate">
DomDocument obtainDocumentByPath(String path);
DomDocument obtainDocumentByUUID(String uuid);
&lt;t extends BaseDasl&gt; CollectionResults obtainDocumentCollection(
    T dasl, boolean completeDocument);
void deleteDocument(String path);
void createDocument(String relativePath, InputStream content);
void updateMetadataForDocument(String relativePath, Property[] props);
</pre>
<p>The last part is using the content connector to actually obtain items from the repository. There are some things you need to take care of, one of them being obtaining data from the returned data. You probably need to do some marshalling and unmarshalling. We used an abstract class to make it easier to create dao classes. The next piece of code is a method from the abstract class, just to give an indication.</p>
<pre class="brush: java; title: ; notranslate">
protected T findItem(String path) {
    DomDocument foundDoc = getContentConnector().obtainDocumentByPath(path);
    if (foundDoc == null) {
        throw new ResourceNotFoundException(&quot;Request not found: &quot; + path);
    }
    return unmarshalHippoDoc(foundDoc);
}
</pre>
<p>That is about it for this blog item. The source is not available online like usual, if you have additional questions, please use the comments.</p>
<p></t></p>
<div class='dd_post_share'><div class='dd_buttons'><div class='dd_button'><iframe src='http://widgets.dzone.com/links/widgets/zoneit.html?url=http%3A%2F%2Fwww.gridshore.nl%2F2008%2F07%2F06%2Fintegrate-hippo-cms-into-a-spring-application%2F&amp;title=Integrate%20hippo%20cms%20into%20a%20spring%20application&amp;t=2' height='25' width='155' frameborder='0' scrolling='no'></iframe></div></div><div style='clear:both'></div></div><!-- Social Buttons Generated by Digg Digg plugin v4.5.3.4, 
    Author : Yong Mook Kim
    Website : http://www.diggdigg2u.com -->]]></content:encoded>
			<wfw:commentRss>http://www.gridshore.nl/2008/07/06/integrate-hippo-cms-into-a-spring-application/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

