Planet Hippo

Niels van Kampenhout (Hippo)Creating a new document through the Hippo Repository Workflow API

June 23, 2009

It's already a couple of months ago that I wrote about using the Hippo Repository Workflow API. Back then, I explained how to modify an existing document, and request publication. Ever since that blog post I have been getting the same question over and over again: how to create a new document through the repository API?

If you read the previous blog post, and looked at the worklfow API, it might not be directly obvious how to create a new document through the workflow. Think about how a document is created though: it is always created as a child node of an existing node: the parent folder. Creating a new document is actually part of the Folder Workflow!

Knowing this, it all becomes very easy. Let's step through the code:

Let's hardcode some values for simplicity's sake:


String folderPath = "/content/documents/news";
String newDocumentName = "Hippo CMS 7.1 released!";
String newDocumentType = "defaultcontent:news";

We will be creating a new document inside the folder /content/documents/news. This is actually a node of type hippostd:folder, which means a FolderWorkflow applies to this node. We will be creating a new document of type "defaultcontent:news", as provided with the Hippo CMS Quickstart WAR. We will call the new document "Hippo CMS 7.1 released!".

Next, we get the folder node from the repository session:

// get the folder node
HippoNode folderNode = (HippoNode) session.getItem(folderPath);

We also need the workflow manager:

// get the workflow manager
HippoWorkspace workspace = (HippoWorkspace) folderNode.getSession().getWorkspace();
WorkflowManager workflowMgr = workspace.getWorkflowManager();

Using the workflow manager, get the folder node's workflow:

// get the folder node's workflow
Workflow workflow = workflowMgr.getWorkflow("internal", folderNode);

Check if the workflow is a folder workflow, and cast it to a FolderWorkflow object:

if (workflow instanceof FolderWorkflow) {
FolderWorkflow fw = (FolderWorkflow) workflow;

Now that we have the folder workflow, we can simply call the add method. It takes three String parameters: the category ("new-document"), the node type, and the node name:

// create the new document
fw.add("new-document", newDocumentType, newDocumentName);

That's it! Run the program, and check your CMS. There should be a new document "Hippo CMS 7.1 Released!" visible under the "news" folder. You can edit and publish this document just like any other. To modify the document through the API, see my previous post on this subject.

For your convenience, here is the complete class:

package org.example;

import java.rmi.RemoteException;

import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.hippoecm.repository.HippoRepository;
import org.hippoecm.repository.HippoRepositoryFactory;
import org.hippoecm.repository.api.HippoNode;
import org.hippoecm.repository.api.HippoWorkspace;
import org.hippoecm.repository.api.Workflow;
import org.hippoecm.repository.api.WorkflowException;
import org.hippoecm.repository.api.WorkflowManager;
import org.hippoecm.repository.standardworkflow.FolderWorkflow;

public class CreateDocument {

public static void main(String[] args) {
Session session;
HippoRepository repository;
try {
repository = HippoRepositoryFactory.getHippoRepository("rmi://localhost:1099/hipporepository");
session = repository.login("author", "author".toCharArray());

String folderPath = "/content/documents/news";
String newDocumentName = "Hippo CMS 7.1 released!";
String newDocumentType = "defaultcontent:news";

// get the folder node
HippoNode folderNode = (HippoNode) session.getItem(folderPath);

// get the workflow manager
HippoWorkspace workspace = (HippoWorkspace) folderNode.getSession().getWorkspace();
WorkflowManager workflowMgr = workspace.getWorkflowManager();

// get the folder node's workflow
Workflow workflow = workflowMgr.getWorkflow("internal", folderNode);

if (workflow instanceof FolderWorkflow) {
FolderWorkflow fw = (FolderWorkflow) workflow;

// create the new document
fw.add("new-document", newDocumentType, newDocumentName);

System.out.println("New document '" + newDocumentName + "' of type '" + newDocumentType + "' created");
}
else {
System.out.println("Workflow is not an instance of FolderWorkflow");
return;
}

} catch (RepositoryException e) {
System.out.println(e.getMessage());
} catch (RemoteException e) {
System.out.println(e.getMessage());
} catch (WorkflowException e) {
System.out.println(e.getMessage());
}
}
}

Tjeerd D. Brenninkmeijer (Hippo)Walking the open source road

At a recent conference, I was approached by an executive from a software company who wanted advice on how they could open their code. I’ve been in open source for many years; early open source developments simply evolved organically as collaborative projects, and there was no ‘right or wrong’

Vijay Kiran (Hippo)Customizing Hippo CMS – Getting Started

June 19, 2009

This post is part of a series which will be focusing mainly on Hippo CMS’s extensibility. These posts are more targeted towards the developers who want to customize and enhance the core CMS functionality.

Introduction

Hippo CMS is part of the Hippo’s Open Source Enterprise Content Management System. It provides a browser based user interface for managing the content in the Hippo Repository. Hippo CMS is fully customizable and developer friendly CMS that provides various ways to extend its functionality.

Hippo CMS application is built using Apache Wicket, one the best frameworks available today for building web applications using Java. Wicket is known for its simplicity, and its component-oriented programming, thus providing solid base for the Hippo CMS.

Hippo CMS has pluggable architecture which boasts of first class plug-in mechanism. Depending on your needs, you can create complex document types, extend and enhance the user interface and even create a combined add-on that can change the Core CMS and even replace. All you need to know to build the GUI add-ons is Java and Wicket.

I’ll try to explain each of these extensibility in detailed examples in this series of blog posts. So let us get started.

Yesterday we have announced a new version of Hippo CMS (version 7.1) and Hippo Site Toolkit 2(Version 2.03.09).

Getting and Building Hippo CMS
I’m assuming you are using a Unixy Operating system (Linux/Mac OS X). If you use windows replace the commands appropriately.

Before starting to checkout the source and building please make sure you have the following installed on your computer.

Open a command line and check out the code for Hippo ECM using following command. Please note that if you are using an graphical client such as Tortose SVN, then you can checkout using the appropriate menu option.

svn co http://svn.onehippo.org/repos/hippo/hippo-ecm/tags/Tag-HREPTWO-v2_06_06 cms-7.1

Now change to the cms-7.1 directory and build the Hippo ECM using maven.

cd cms-7.1
mvn clean install [-DskipTests]

If you are getting out of heap space error, set the MAVEN_OPTS using the following command:

export MAVEN_OPTS="-Xms256m -Xmx700m -XX:MaxPermSize=1024m"

If you are building for the first time, please note that it may take some time since maven needs to download all the dependencies. Once you are done with building Hippo ECM and you can run the provided Quick-start WAR file to get a feel of the user interface and the CMS application.

Change to the quickstart/war directory and run the hippo-cms web application using embedded jetty.

cd quickstart/war
mvn jetty:run-war

After jetty has been started, goto http://localhost:8080/cms to check the version of the CMS that you’ve just built. You can login using default username/password combination of admin/admin.

HippoCMS001

Hippo CMS Login Screen

Note that you can even deploy the generated war file in Tomcat or an Application Server. Check the documentation for more information.

This concludes the first part of Hippo CMS Customization Part 1- Getting Started . In the next post of this series we will see how to create a simple backend templates (a.k.a Document Types) using Document Type Editor provided within Hippo CMS.

Mathijs Brand (Hippo)Limited choices

June 15, 2009

Coffee choices... I don't like to make choices. For me the best choice in life is - no choice at all. For example: I like to drink coffee. Any kind

Jeroen Reijn (Hippo)JCR: Sorting on child node properties

June 13, 2009

A JCR repository, like Apache Jackrabbit (basis for Hippo CMS 7's content repository), mainly consists of nodes and properties.
As described in the JCR specification, a Java Content Repository should support 2 different query syntaxes: XPath and SQL. Once you get the hang of the syntax, performing a search on a JCR repository is quite easy, but today I came into a situation where I was not able perform the query I wanted. In this post I'll try to describe what my problem was and how the same result can still be achieved.

The content model


Let's first start with my content model. The actual node definition for my project looks something like the below:


[myproject:metadata]
- myproject:creator (string)
- myproject:language (string)
- myproject:publicationDate (date)
- myproject:availableUntil (date)
- myproject:lastModified (date)
- myproject:keywords (string)
- myproject:contributor (string)

[myproject:news] > hippostd:publishable, hippostd:publishableSummary, hippo:document
- myproject:title (string)
+ myproject:introduction (hippostd:html)
+ myproject:body (hippostd:html)
+ myproject:metadata (myproject:metadata)


I came into a situation where I wanted to search for nodes of type 'myproject:news', but sorted on the 'myproject:publicationDate' property of the 'myproject:metadata' subnode. Writing an XPath for such a query is quite easy if you're familiar with the XPath syntax.

Let's start out with a very simple search and just search for nodes of the type 'myproject:news' , which in XPath looks like:


//element( *, myproject:news)


Now if we would want to order these node types based on for instance the myproject:title property the same XPath query looks like:


//element( *, myproject:news) order by @myproject:title descending


Now if we would want to sort on the 'myproject:publicationDate' property of the myproject:metadata subnode, I would expect the same XPath to be:


//element( *, myproject:news) order by myproject:metadata/@myproject:publicationDate descending


Unfortunately this query did not seem to actually sort the result on the publicatenDate property as I would have expected. I was searching for typos first, but it appeared that the syntax of my query was ok, but it appeared that support for child axis in order by clauses was not yet supported by Jackrabbit itself.

Then I found this JIRA issue[1] in the Jackrabbit bugtracker describing this problem and there appears to be a patch available. I'm still wondering how much of a performance impact this might have for large repositories, where you might want to sort on a property of a child node 'n'-levels deep underneath the actual node.

If you want to sort on properties of a specific nodetype, you will have to add the sortable properties to the actual nodetype, which you are searching for and can't put them on a subnode.
It seems that the patch, which should fix this problem, has already been comitted to the Jackrabbit trunk and should be available from Jackrabbit 1.6.0 as marked in the JackRabbit JIRA.

Woonsan Ko (Hippo)Spring Web MVC framework support in HST-2

June 05, 2009

Spring Web MVC framework support in HST-2


HST-2 has provided a basic support to enable developers to utilize Spring Framework IoC container for HST components. [1]
Now, HST-2 provides even more. It supports Spring Web MVC Framework based applications under HST-2 environment! Using

Jasha Joachimsthal (Hippo)Hippo Site Toolkit Query interface and pagination

June 04, 2009

Today an interesting question came from a developer of one of our implementation partners. He wanted to list items from our JCR repository and use pagination. In this post I tried to make a summary out of the conversation.

The query was:

HstQuery query = getQueryManager().createQuery(requestContext, scope, filterBean);
Filter filter = query.createFilter();
filter.addContains(".", "my keywords");
query.setFilter(filter);
HstQuery queryResult = query.execute();

The developer tried to get a paged result and the total number of items with:

query.setOffset(0);
query.setLimit(10);

HippoBeanIterator hits = queryResult.getHippoBeans();        
hits.getSize();

The result contained indeed 10 items but hits.getSize(); also returned 10. What's going wrong? Ard Schrijvers explained:

If you use setLimit(3), you will get at most 3 hits, but never more. getSize() from the queryResult returns at most 3. Even if the search criteria matched hundreds of documents. If you use offset(10) and no limit, getSize() returns just 10 hits less then without the offset.

This limit is there to be used for performance, and suits for example very well "show last 3 agenda items on homepage".

If you need paging and only want 10 results, do not use setLimit(int limit).

What you do use, is just the query without setLimit(). Then you'll get back a queryResult, from which you get a HippoBeanIterator. This is a normal Iterator, with some extensions. A very important one is the method skip(int skipNum).

From the HippoBeanIterator, you can simply iterate the beans you need. Make sure you use skip(int skipNum) to jump to the correct place. If the current page is 11 and pagesize is 20, set skipNum to 220.

Then fill your List in a for loop from skipNum - skipNum + pageSize.

What about performance?

The skip is propagated to the JCR NodeIterator. If you want to display item 100-110, and you use skip(100), still only 10 Beans will be created. JCR nodes for Beans 0-99 are not fetched.

What if you need the total number of hits?

Use getSize(). The getSize() on the the HstQueryResultImpl or on the HippoBeanIteratorImpl does not actually populate the entire iterator with HippoBeans. It is a call through the JCR NodeIterator, which in JackRabbit is some lazy loading iterator, and, where the getSize is propagated to the executed query, without fetching actual nodes.