Creating a portlet to integrate JBoss ModeShape

In this recipe, we will see how GateIn communicates with another ECM repository, JBoss ModeShape.

ModeShape is a JCR implementation provided by the JBoss Community. The main feature that makes it stand out is the repository federation.

Note

The federation provides a single JCR interface for accessing and searching contents coming from different backend systems. You might think of a ModeShape repository containing information from a relational database, a filesystem, and perhaps even another Java content repository, for instance, Hippo CMS 7's content repository.

In this recipe, you will see some examples of a portlet that communicates with a ModeShape endpoint.

Getting ready

To follow this recipe, you will need:

  • Maven 3.x
  • A GateIn 3.2.0 installation (JBoss or Tomcat)
  • ModeShape 2.8.1

ModeShape will be installed automatically through Maven. We will create two portlets, with one making a local connection and the other connecting remotely remotely to the repository to access the content.

How to do it...

In this sample, you will learn how to bootstrap a ModeShape repository at runtime using Maven. Let's look at the required steps:

  1. Create the Maven pom.xml file as follows:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>my.gatein</groupId>
      <artifactId>ModeshapePortlet</artifactId>
      <packaging>war</packaging>
      <version>0.0.1-SNAPSHOT</version>
    
      <dependencies>
        <dependency>
          <groupId>javax.portlet</groupId>
          <artifactId>portlet-api</artifactId>
          <version>2.0</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>javax.jcr</groupId>
          <artifactId>jcr</artifactId>
          <version>2.0</version>
        </dependency>
        <dependency>
          <groupId>org.modeshape</groupId>
          <artifactId>modeshape-jcr</artifactId>
          <version>2.8.1.Final</version>
        </dependency>
        <dependency>
          <groupId>org.modeshape</groupId>
          <artifactId>modeshape-cnd</artifactId>
          <version>2.8.1.Final</version>
        </dependency>
        <dependency>
          <groupId>org.modeshape</groupId>
          <artifactId>modeshape-connector-store-jpa</artifactId>
          <version>2.8.1.Final</version>
        </dependency>
        <dependency>
          <groupId>org.modeshape</groupId>
          <artifactId>modeshape-connector-filesystem</artifactId>
          <version>2.8.1.Final</version>
        </dependency>
        <dependency>
          <groupId>org.modeshape</groupId>
          <artifactId>modeshape-web-jcr-rest-client</artifactId>
          <version>2.8.1</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.5.8</version>
        </dependency>
      </dependencies>
    </project>
  2. In portlet.xml, declare the two portlets as follows:
    <?xml version="1.0" encoding="UTF-8"?>
    <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
      version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
       http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
      <portlet>
        <portlet-name>LocalModeshapePortlet</portlet-name>
        <portlet-class>my.gatein.LocalModeshapePortlet</portlet-class>
        <supports>
          <mime-type>text/html</mime-type>
          <portlet-mode>view</portlet-mode>
          <portlet-mode>edit</portlet-mode>
          <portlet-mode>help</portlet-mode>
        </supports>
        <portlet-info>
          <title>Modeshape Local Portlet</title>
        </portlet-info>
      </portlet>
      <portlet>
        <portlet-name>RemoteModeshapePortlet</portlet-name>
        <portlet-class>my.gatein.RemoteModeshapePortlet</portlet-class>
        <supports>
          <mime-type>text/html</mime-type>
          <portlet-mode>view</portlet-mode>
          <portlet-mode>edit</portlet-mode>
          <portlet-mode>help</portlet-mode>
        </supports>
        <portlet-info>
          <title>Modeshape Remote Portlet</title>
        </portlet-info>
      </portlet>
    </portlet-app>
  3. For the local connection, create a simple class my.gatein.LocalModeshapePortlet. In the following sample, you will create a new repository session in the processAction method:
    import org.modeshape.jcr.JcrRepositoryFactory;
    import java.util.ServiceLoader;
    import javax.portlet.*;
    import javax.jcr.*;
    ...
    
       @Override
      public void processAction(ActionRequest request, ActionResponse response)
          throws PortletException, IOException {
    
        Properties parameters = new Properties();
        parameters.put("org.modeshape.jcr.URL",
            "file:/configRepository.xml?repositoryName=Cars");
        Repository repository = null;
    
        for (RepositoryFactory factory : ServiceLoader
            .load(RepositoryFactory.class)) {
          if (factory instanceof JcrRepositoryFactory)
            try {
              repository = factory.getRepository(parameters);
              Session session = (Session) repository.login("workspace1");
              Node root = (Node) session.getRootNode();
              printAllNodes(root, "");
    
            } catch (RepositoryException e) {
              e.printStackTrace();
            }
        }
      }
  4. Put the XML configuration files of ModeShape in the src/main/resources folder of your Maven project. The example used is a repository for vehicles; it can be found in the ModeShape 2.8.1 source or by connecting directly to a code search engine. You can download grepcode from this URL: http://grepcode.com/snapshot/repository.jboss.org/nexus/content/repositories/releases/org.modeshape.examples/modeshape-example-repositories/2.8.1.Final/

    Copy the following required configuration files:

    • configRepository.xml: This is the main configuration file. It declares a federated vehicles repository composed of cars represented by an in-memory repository, airplanes represented by a JPA repository, and UFOs represented by a file-system repository.
    • cars.cnd: This is the descriptor for the cars. It declares the structure of a JCR car node.
    • aircraft.cnd: This is the descriptor for the airplanes. It declares the structure of a JCR aircraft node.
  5. Now let us consider the Remote portlet. This time you don't need the configuration files because we expect the ModeShape repository to be installed remotely. The only difference in the local portlet is the actionProcess method of the my.gatein.RemoteModeshapePortlet:
    import javax.portlet.*;
    import javax.jcr.*;
    import org.modeshape.web.jcr.rest.client.IRestClient;
    import org.modeshape.web.jcr.rest.client.domain.QueryRow;
    import org.modeshape.web.jcr.rest.client.domain.Repository;
    import org.modeshape.web.jcr.rest.client.domain.Server;
    import org.modeshape.web.jcr.rest.client.domain.Workspace;
    import org.modeshape.web.jcr.rest.client.json.JsonRestClient;
    ...  
    
       @Override
      public void processAction(ActionRequest request, ActionResponse response)
          throws PortletException, IOException {
    
        Server server = new Server(REMOTE_SERVER_URL, "username", "password");
        Repository repository = new Repository("Cars", server);
        Workspace workspace = new Workspace("workspace1", repository);
    
        IRestClient restClient = new JsonRestClient();
        try {
          List<QueryRow> rows = restClient.query(workspace, "xpath", "//*");
          ...
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
  6. The following code can be used to get nodes from the repository:
      public void printAllNodes(Node root, String space)
          throws RepositoryException {
        NodeIterator nodeIterator = (NodeIterator) root.getNodes();
        while (nodeIterator.hasNext()) {
          Node node = (Node) nodeIterator.nextNode();
          System.out.println(space + node);
          System.out.println();
          PropertyIterator pi = node.getProperties();
          while (pi.hasNext()) {
            Property property = pi.nextProperty();
            System.out
                .println(space
                    + "------------------------------------------------------");
            System.out.print(space + property.getName() + " - ");
            try {
              System.out.println(property.getValue().getString());
            } catch (ValueFormatException e) {
              for (Value value : property.getValues())
                System.out.print(value.getString() + " - ");
              System.out.println();
            }
          }
          printAllNodes(node, space + "   ");
        }
      }
  7. Build the Maven project and install the created WAR and portlets files in your portal as seen in the previous chapters.
  8. Click on the Local Controller ModeShape link shown in the body of the window of the Local ModeShape Portlet. You will see in the log the complete list of the nodes of the workspace1 workspace.

How it works...

In the pom.xml file, we declare enough libraries to execute an interaction with ModeShape. Of course, ModeShape provides several other plugins that we don't need to show in this recipe.

You can see the standard portlet and JCR API libraries needed for the creation of the portlet and the interaction with a common JCR repository.

The modeshape-jcr project is the core JCR implementation. The modeshape-cnd reads the cnd configuration files used to represent the JCR nodes structure.

If you look at the configRepository.xml file, you will see the declaration of a federated repository named Vehicles:

<mode:source jcr:name="Vehicles">
            <mode:classname>org.modeshape.graph.connector.federation.FederatedRepositorySource</mode:classname>
   <mode:workspaces>
      <mode:workspace jcr:name="virtual">
         <mode:projections>
             <!-- Project the 'Cars' content, starting with the '/Cars' node. -->
             <mode:projection jcr:name="Cars projection" mode:source="Cars" mode:workspaceName="workspace1">
                             
                <mode:projectionRules>/Vehicles/Cars => /Cars</mode:projectionRules>
             </mode:projection>
             <!-- Project the 'Aircraft' content, starting with the '/Aircraft' node. -->
             <mode:projection jcr:name="Aircarft projection" mode:source="Aircraft" mode:workspaceName="workspace2">
                             
                <mode:projectionRules>/Vehicles/Aircraft => /Aircraft</mode:projectionRules>
             </mode:projection>
             <!-- Project the 'UFOs' content, starting with the root node. -->
             <mode:projection jcr:name="UFO projection" mode:source="UFOs" mode:workspaceName="workspace1">
                            <mode:projectionRules>/Vehicles/UFOs => /</mode:projectionRules>
             </mode:projection>
</mode:projections>
     </mode:workspace>
   </mode:workspaces>
</mode:source>

The Vehicles repository virtualizes all the three repositories: Cars, Aircrafts, and UFOs. The UFOs repository maintains the references in the filesystem through the modeshape-connector-filesystem project. The Aircraft repository needs the modeshape-connector-jpa project to be restored through the JPA framework.

The slf4j-log4j12 library is required for ModeShape. Always use the current version used by GateIn, 1.5.8, to avoid confusion between the versions.

In this sample, we are using JCR 2.0 API instead of the 1.0 version used by eXo JCR. This version allows us to use the javax.jcr.RepositoryFactory class that can be discovered as a service by the java.util.ServiceLoader class of the Java 6 API.

Note

The ServiceLoader is a utility class provided by Java for loading services as an extension mechanism. A service is a set of interfaces and concrete classes that you need to add features to the application in a clean and transparent way.

This approach allows you to extend any Java application dropping new resources in an external path/package. These external services will be registered as components.

For GateIn, each extension must implement the interface org.gatein.management.spi.ManagementExtension, and GateIn will look up for extensions under the path /META-INF/services.

For more information about ServiceLoader, please visit http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html.

This is because the file META-INF/services/javax.jcr.RepositoryFactory is set in the modeshape-jcr library, containing the implementation row:

org.modeshape.jcr.JcrRepositoryFactory # ModeShape JCR Implementation

In this manner, if you need to use different JCR repositories, you can use the same client to find them and filter them using similar code:

if (factory instanceof JcrRepositoryFactory)
  ...
else 
   ...

Through the org.modeshape.jcr.URL property passed to the JCR factory.getRepository(parameters) operation , the configuration file is read and the working repository is found thanks to the parameter value ?repositoryName=Cars.

The login operation starts the ModeShape repository. At first login, all objects are created and persisted in the filesystem or in the database according to the configuration of configRepository.xml.

When the thread ends, the repository also ends.

The remote connection needs the Rest API for ModeShape. This is installed through the modeshape-web-jcr-rest-client library declared in the pom.xml.

The remote connection needs a server configuration for ModeShape. It can be configured together with a webdav server. See Chapter 8, Migrating from Existing Portals for some information on webdav, or see the Red Hat doc for complete information on how to configure webdav in ModeShape:

http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Data_Services/5/html/Metadata_Repository_Reference_Guide/web_access.html

See also

  • The Migrating a portlet that uses JCR recipe in Chapter 8, Migrating from Existing Portals
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.79.241