Apache Pluto & Jackrabbit Integration Example Tutorial

Filed Under: Portal and Portlets

According for multiple sources and standards, you may be able of defining the Content Repository as a store of digital content (Structured/Unstructured) with an associated set of facilities like data management, full-text search, versioning, transactions and access methods allowing application-independent access the content.

Accessing these content has become important matter as this should be done through using of a well-defined, common standard and organized way. This actually will help you getting acquired a lot of features, most important one of them is Swap-ability.

This exactly means that when it comes to modify your Content Engine, you don’t wast a lot of time/efforts acquiring/learning practices & information to get this new Content Repository integrated into your infrastructure.

As the importance of the Portal has increased the need for the integration with Content Repository is also got increased and especially when you know that a very famous Portal like WebLogic Portal has become self-integrated with one of the most robust content management system which was known as a Stellent-UCM (Currently know as oracle Stellent-UCM).

Even though a Stellent UCM has already provided a separate API to get integrated with, however Oracle has integrated through controls built in using JCR/JSR 170

Numerous kinds of content repositories are provided these days, some of them are Open source like Apache Jackrabbit while others are still closed source and you may find something restricted like Alfresco.

This restriction comes in terms of availability for a community copy but if you want more powerful support you may need to buy a license.

This tutorial is a solid trial that aim to provide you tangible perspective for the Content Repository concept and how can you use that JCR standard API to get integrated with as well as provide you other options that you may need to communicate with other repositories that may or may not provide you a standard way to communicate with.

Running Jackrabbit Into Apache

Defining of Apache Jackrabbit isn’t separated from defining of the JCR itself, JCR is stands for Java Content Repository or Content Repository API for Java, it’s a specification for Java platform to access content repositories in a uniform manner.

Apache Jackrabbit content repository is a complete, and fully complaint implementation of the Content Repository API for Java Technology API (JCR – Java Content Repository) and therefore its primary API is defined by JCR.

Jackrabbit supports all JCR specifications, practically, Jackrabbit 2.8 supports JCR 2.0 while last version of Jackrabbit that supports JCR 1.0 was Jackrabbit 1.6.

To get started using of Jackrabbit content repository and communicating with it through using of standard JCR 2.0, just follow below steps:

  • Download Jackrabbit from Apache official site.
  • Unzip Jackrabbit into your directory. We assumed that you did that on D:\Jackrabbit\jackrabbit-2.8.0.
  • Open your jackrabbit-webapp and modify populate.jsp there to be look like below:

populate.jsp


<%--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
--%><%@ page import="java.io.FilterInputStream,
                     java.io.IOException,
                     java.io.InputStream,
                     java.io.InputStreamReader,
                     java.net.URL,
                     java.net.URLConnection,
                     java.net.URLDecoder,
                     java.net.URLEncoder,
                     java.util.ArrayList,
                     java.util.Arrays,
                     java.util.Calendar,
                     java.util.Collections,
                     java.util.Iterator,
                     java.util.List,
                     javax.jcr.Node,
                     javax.jcr.Repository,
                     javax.jcr.Session,
                     javax.jcr.SimpleCredentials,
                     org.apache.jackrabbit.j2ee.RepositoryAccessServlet,
                     org.apache.jackrabbit.util.Text,
                     org.json.simple.JSONArray,
                     org.json.simple.JSONObject,
                     org.json.simple.JSONValue"
 %><%@ page contentType="text/html;charset=UTF-8" %><%
    Repository rep;
    Session jcrSession;
    String wspName;
    try {
        rep = RepositoryAccessServlet.getRepository(pageContext.getServletContext());
        jcrSession = rep.login(new SimpleCredentials("admin", "admin".toCharArray()));
        wspName = jcrSession.getWorkspace().getName();
    } catch (Throwable e) {
        %>Error while accessing the repository: <font color="red"><%= Text.encodeIllegalXMLCharacters(e.getMessage()) %></font><br><%
        %>Check the configuration or use the <a href="admin/">easy setup</a> wizard.<%
        return;
    }
    try {
        String seedWord = request.getParameter("seed");
        if (seedWord != null) {
            seedWord = new String(seedWord.getBytes("ISO-8859-1"), "UTF-8");
        }
        int numDocs = 0;
        List filetypes = new ArrayList();
        if (request.getParameter("num") != null) {
            try {
                numDocs = Integer.parseInt(request.getParameter("num"));
            } catch (NumberFormatException e) {
                // ignore
            }
        }
        String[] types = request.getParameterValues("filetype");
        if (types != null) {
            filetypes.addAll(Arrays.asList(types));
        } else {
            filetypes = DEFAULT_TYPES;
        }

if (seedWord != null && numDocs > 0 && filetypes.size() > 0) { %>
<html>
<head>
<title>Welcome to Apache Jackrabbit - Populate workspace: <%= Text.encodeIllegalXMLCharacters(wspName) %></title>
<link rel="shortcut icon" href="<%= Text.encodeIllegalXMLCharacters(request.getContextPath()) %>/images/favicon.ico" type="image/vnd.microsoft.icon">
<style type="text/css" media="all">
      @import url("<%= Text.encodeIllegalXMLCharacters(request.getContextPath()) %>/css/default.css");
</style>
<script><!--
function draw() {
	// draw the bar
        document.write('<table cellspacing="0" cellpadding="0" style="border-color:' + this.borderColor + '; border-width:' + this.borderWidth + '; border-style:' + this.borderStyle + '">');
        document.write('<tr><td>');
        document.write('<table border="0" cellspacing="0" cellpadding="0" style="">');
        document.write('<tr><td style="background-color:' + this.barColor +'"><img src="<%= Text.encodeIllegalXMLCharacters(request.getContextPath()) %>/images/0.gif" id="' + this.id + 'barFG" width="0" height="' + this.height + '"/></td>');
        document.write('<td><img src="<%= Text.encodeIllegalXMLCharacters(request.getContextPath()) %>/images/0.gif" id="' + this.id + 'barBG" width="' + this.width + '" height="' + this.height + '"/></td></tr>');
        document.write('</table>');
        document.write('</tr></td>');
        document.write('</table>');
        document.write('<table>');
        document.write('<tr><td><img src="<%= Text.encodeIllegalXMLCharacters(request.getContextPath()) %>/images/0.gif" width="' + this.width + '" height="0"/></td></tr>');
        document.write('<tr><td align="center"><span id="' + this.id + 'barValue">0%</span></td></tr>');
        document.write('<tr><td align="center"><span id="' + this.id + 'barInfo"> </span></td></tr>');
        document.write('</table>');

	this.barFG = document.getElementById(this.id + 'barFG');
	this.barBG = document.getElementById(this.id + 'barBG');
	this.barValue = document.getElementById(this.id + 'barValue').firstChild;
	this.barInfo = document.getElementById(this.id + 'barInfo').firstChild;
}

// informs the progress bar about the current value
function inform(value, info) {
	var barWidth = Math.floor(this.width * value / this.maxValue);
	var spaceWidth = this.width - barWidth;
	var perCent = Math.floor(100 * value / this.maxValue);
	this.barFG.width = barWidth;
	this.barBG.width = spaceWidth;
	this.barValue.nodeValue = perCent + '%';
	this.barInfo.nodeValue = info;
}

// constructor
function ProgressBar(maxValue, width, height) {
	this.maxValue = maxValue;
	this.width = width;
	this.height = height;
	this.id = '' + Math.round(Math.random() * 10000);
	this.inform = inform;
	this.draw = draw;
}

// default values
ProgressBar.prototype.barColor = "green";
ProgressBar.prototype.borderColor = "grey";
ProgressBar.prototype.borderStyle = "groove";
ProgressBar.prototype.borderWidth = "2px";

// -->
</script>
</head>
  <body>
  <div style="background: white; border: 1px solid black; padding: 50px; width: 510px; margin: 50px auto;">
  <h2>Populate workspace: "<%= Text.encodeIllegalXMLCharacters(wspName) %>"</h2><br>
    <p>Overall progress</p>
    <script>var pb = new ProgressBar(<%= numDocs %>, 500, 30);pb.draw();</script>

    <p>Downloading document</p>
    <script>var dp = new ProgressBar(1000, 500, 30);dp.draw();</script>
    <%
            Node root = jcrSession.getRootNode();
            int n = 0;
            for (int typeIdx = 0; typeIdx < filetypes.size(); typeIdx++) {
                String type = (String) filetypes.get(typeIdx);
                int offset = 0;
                while (n < numDocs * (typeIdx + 1) / filetypes.size()) {
                    final URL[] urls = new Search(type, seedWord, offset).getURLs();
                    if (urls.length == 0) {
                        break;
                    }
                    for (int i = 0; i < urls.length; i++) {
                        final URL currentURL = urls[i];
                        String path = urls[i].getPath();
                        if (path.startsWith("/")) {
                            path = path.substring(1);
                        }
                        final String host = urls[i].getHost();
                        List folderNames = new ArrayList();
                        folderNames.addAll(Arrays.asList(host.split("\\.")));
                        Collections.reverse(folderNames);
                        folderNames.addAll(Arrays.asList(path.split("/", 0)));
                        final String fileName = URLDecoder.decode((String) folderNames.remove(folderNames.size() - 1), "UTF-8").replaceAll(":", "_");
                        Node node = root;
                        for (Iterator fn = folderNames.iterator(); fn.hasNext(); ) {
                            String name = URLDecoder.decode((String) fn.next(), "UTF-8");
                            name = name.replaceAll(":", "_");
                            if (name.length() == 0) {
                                continue;
                            }
                            if (!node.hasNode(name)) {
                                node.addNode(name, "nt:folder");
                            }
                            node = node.getNode(name);
                        }
                        if (!node.hasNode(fileName)) {
                            final JspWriter fOut = out;
                            Node file = node.addNode(fileName, "nt:file");
                            final Node resource = file.addNode("jcr:content", "nt:resource");
                            final Exception[] ex = new Exception[1];
                            Thread t = new Thread(new Runnable() {
                                public void run() {
                                    try {
                                        String info = fileName + " (" + host + ")";
                                        URLConnection con = currentURL.openConnection();
                                        InputStream in = con.getInputStream();
                                        try {
                                            synchronized (fOut) {
                                                fOut.println("<script>dp.inform(0, '" + Text.encodeIllegalXMLCharacters(info) + "')</script>");
                                                fOut.flush();
                                            }
                                            int length = con.getContentLength();
                                            if (length != -1) {
                                                in = new ProgressInputStream(in, length, info, "dp", fOut);
                                            }
                                            resource.setProperty("jcr:data", in);
                                            String mimeType = URLConnection.guessContentTypeFromName(fileName);
                                            if (mimeType == null) {
                                                if (fileName.endsWith(".doc")) {
                                                    mimeType = "application/msword";
                                                } else if (fileName.endsWith(".xls")) {
                                                    mimeType = "application/vnd.ms-excel";
                                                } else if (fileName.endsWith(".ppt")) {
                                                    mimeType = "application/mspowerpoint";
                                                } else {
                                                    mimeType = "application/octet-stream";
                                                }
                                            }
                                            resource.setProperty("jcr:mimeType", mimeType);
                                            Calendar lastModified = Calendar.getInstance();
                                            lastModified.setTimeInMillis(con.getLastModified());
                                            resource.setProperty("jcr:lastModified", lastModified);
                                        } finally {
                                            in.close();
                                        }
                                    } catch (Exception e) {
                                        ex[0] = e;
                                    }
                                }
                            });
                            t.start();
                            for (int s = 0; t.isAlive(); s++) {
                                Thread.sleep(100);
                                if (s % 10 == 0) {
                                    synchronized (fOut) {
                                        fOut.println("<script>pb.inform(" + n + ", '')</script>");
                                        fOut.flush();
                                    }
                                }
                            }
                            if (ex[0] == null) {
                                jcrSession.save();
                                n++;
                                synchronized (fOut) {
                                    fOut.println("<script>pb.inform(" + n + ", '')</script>");
                                    fOut.flush();
                                }
                                if (n >= numDocs * (typeIdx + 1) / filetypes.size()) {
                                    break;
                                }
                            } else {
                                jcrSession.refresh(false);
                            }
                        }
                    }
                    offset += 10;
                }
            }
%>  </div>
  </body>
</html>
<% } else {
request.setAttribute("title", "Populate workspace " + wspName);
%><jsp:include page="header.jsp"/>
<p>
  This page allows you to populate the workspace with documents downloaded
  from the Internet.
</p>
    <form method="POST">
      <table>
      <tr><td>Seed word (optional):</td><td><input name="seed" type="text" size="30" value="<%= seedWord == null ? "" : Text.encodeIllegalXMLCharacters(seedWord) %>"/></td></tr>
      <tr><td>Number of documents:</td><td><input name="num" type="text" size="30" value="<%= numDocs == 0 ? 100 : numDocs %>"/></td></tr>
      <tr valign="top"><td>Document types:</td><td><input name="filetype" type="checkbox" value="pdf" <%= filetypes.contains("pdf") ? "checked" : "" %>/> Adobe Acrobat PDF<br/><input name="filetype" type="checkbox" value="rtf" <%= filetypes.contains("rtf") ? "checked" : "" %>/> Rich Text Format<br/><input name="filetype" type="checkbox" value="doc" <%= filetypes.contains("doc") ? "checked" : "" %>/> Microsoft Word<br/><input name="filetype" type="checkbox" value="ppt" <%= filetypes.contains("ppt") ? "checked" : "" %>/> Microsoft PowerPoint<br/><input name="filetype" type="checkbox" value="xls" <%= filetypes.contains("xls") ? "checked" : "" %>/> Microsoft Excel<br/></td></tr>
      <tr><td> </td><td><input type="submit" value="Populate!"/></td></tr>
      </table>
    </form>
<jsp:include page="footer.jsp"/>
<%    }
    } finally {
        if (jcrSession != null) {
            jcrSession.logout();
        }
    }
%><%!

    public static final List DEFAULT_TYPES = Arrays.asList(
            new String[]{"pdf", "rtf", "doc", "ppt", "xls"});

    public static class Search {

        private static final String CHARSET = "UTF-8";

        private final String filetype;

        private final String term;

        private final int start;

        public Search(String filetype, String term, int start) {
            this.filetype = filetype;
            this.term = term;
            this.start = start;
        }

        public URL[] getURLs() throws Exception {
            List<URL> urls = new ArrayList<URL>();
            String googleBaseUrl = "http://ajax.googleapis.com/ajax/services/search/web";
            String googleQueryString = "?v=1.0&start=" + start + "&rsz=8&q=";
            String query = term + " filetype:" + this.filetype;
            URL google = new URL(googleBaseUrl + googleQueryString + URLEncoder.encode(query, CHARSET));
            InputStreamReader reader = null;
            try {
                URLConnection conn = google.openConnection();
                conn.setRequestProperty("Referer", "http://jackrabbit.apache.org/");
                reader = new InputStreamReader(conn.getInputStream(), CHARSET);
                Object obj = JSONValue.parse(reader);
                JSONObject jsonObject = (JSONObject) obj;
                JSONObject responseData = (JSONObject) jsonObject.get("responseData");
                if (responseData != null) {
                    JSONArray results = (JSONArray) responseData.get("results");
                    if (results != null) {
                        for (int i = 0; i < results.size(); i++) {
                            JSONObject result = (JSONObject) results.get(i);
                            if (result != null) {
                                String urlString = (String) result.get("url");
                                URL url = new URL(new URL("http", "www.google.com", "dummy"), urlString);
                                if (!url.getHost().contains("google")) {
                                    urls.add(url);
                                }
                            }
                        }
                    }
                }
            } finally {
                reader.close();
            }
            return urls.toArray(new URL[urls.size()]);
        }
    }

    public static class ProgressInputStream extends FilterInputStream {

        private final int length;

        private final String fileName;

        private final String varName;

        private final JspWriter out;

        private long read;

        private long nextReport = (16 * 1024);

        public ProgressInputStream(InputStream in, int length, String fileName,
                                   String varName, JspWriter out) {
            super(in);
            this.length = length;
            this.fileName = fileName;
            this.varName = varName;
            this.out = out;
        }

        public int read() throws IOException {
            int r = super.read();
            reportProgress(r);
            return r;
        }

        public int read(byte b[]) throws IOException {
            int r = super.read(b);
            reportProgress(r);
            return r;
        }

        public int read(byte b[], int off, int len) throws IOException {
            int r = super.read(b, off, len);
            reportProgress(r);
            return r;
        }

        private void reportProgress(int r) throws IOException {
            if (r != -1) {
                read += r;
                if (read > nextReport || read == length) {
                    // report every 16k
                    synchronized (out) {
                        double s = 1000d * (double) read / (double) length;
                        out.println("<script>" + varName + ".inform(" +
                                Math.min((int) Math.ceil(s), 1000) +
                                ", '" + Text.encodeIllegalXMLCharacters(fileName) + "')</script>");
                        out.flush();
                    }
                    nextReport += (16 * 1024);
                }
            }
        }
    }
%>
  • Execute mvn clean install against your jackrabbit-webapp project.
  • you already have a Maven installed into your machine as well as ready system variables.
  • You should get success build for your later Maven command like below.
  • Open your Eclipse.
  • Create new Apache Tomcat 7 server.
  • Configure created Apache Tomcat by setting Server locations like below:

Configure Apache Tomcat 7 - Server Location

  • Deploy Jackrabbit Web Application from your jackrabbit-webapp project.
  • Download JCR 2.0 API JAR from here into your Apache Tomcat lib.

Deploy Jackrabbit Web Application Copy JCR JAR Into Apache Tomcat Library Folder

  • Run your Tomcat Server from your Eclipse.

Apache Tomcat Is Running

  • Access http://localhost:8080/jackrabbit-webapp-2.8.0/ to open the home page of Apache Jackrabbit.

Jackrabbit - Index Page

  • Create new repository by clicking on Create Content Repository. Your repository home directory will be jackrabbit just like you see above.

Repository Created Successfully

  • Now, you may find below my Repository configurations listed at the console of Eclipse as well as the Repository of mine is created on D:\JournalDev\eclipse\jackrabbit.

Jackrabbit Configurations


2014-12-30 20:42:34.499 INFO  [http-bio-8080-exec-7] Installer.java:159 Creating new repository home 'jackrabbit'
2014-12-30 20:42:34.500 INFO  [http-bio-8080-exec-7] Installer.java:197 Creating new repository config: jackrabbit\repository.xml
2014-12-30 20:42:34.505 INFO  [http-bio-8080-exec-7] Installer.java:221 Creating new bootstrap properties: jackrabbit\bootstrap.properties
2014-12-30 20:42:34.527 INFO  [http-bio-8080-exec-7] RepositoryStartupServlet.java:253 RepositoryStartupServlet initializing...
2014-12-30 20:42:34.528 INFO  [http-bio-8080-exec-7] AbstractConfig.java:101 Configuration of BootstrapConfig
2014-12-30 20:42:34.528 INFO  [http-bio-8080-exec-7] AbstractConfig.java:102 ----------------------------------------------
2014-12-30 20:42:34.536 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   valid: true
2014-12-30 20:42:34.536 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   rmiConfig: org.apache.jackrabbit.j2ee.RMIConfig@36db4bcf
2014-12-30 20:42:34.536 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   repositoryConfig: jackrabbit\repository.xml
2014-12-30 20:42:34.537 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   class: class org.apache.jackrabbit.j2ee.BootstrapConfig
2014-12-30 20:42:34.537 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   repositoryHome: jackrabbit
2014-12-30 20:42:34.537 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   repositoryName: jackrabbit.repository
2014-12-30 20:42:34.537 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   jndiConfig: org.apache.jackrabbit.j2ee.JNDIConfig@774e1f2b
2014-12-30 20:42:34.537 INFO  [http-bio-8080-exec-7] AbstractConfig.java:108 ----------------------------------------------
2014-12-30 20:42:34.537 INFO  [http-bio-8080-exec-7] AbstractConfig.java:101 Configuration of JNDIConfig
2014-12-30 20:42:34.538 INFO  [http-bio-8080-exec-7] AbstractConfig.java:102 ----------------------------------------------
2014-12-30 20:42:34.538 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   valid: true
2014-12-30 20:42:34.538 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   jndiName: jackrabbit.repository
2014-12-30 20:42:34.538 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   jndiEnabled: true
2014-12-30 20:42:34.538 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   class: class org.apache.jackrabbit.j2ee.JNDIConfig
2014-12-30 20:42:34.538 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   jndiEnv: {java.naming.provider.url=http://www.apache.org/jackrabbit, java.naming.factory.initial=org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory}
2014-12-30 20:42:34.539 INFO  [http-bio-8080-exec-7] AbstractConfig.java:108 ----------------------------------------------
2014-12-30 20:42:34.539 INFO  [http-bio-8080-exec-7] AbstractConfig.java:101 Configuration of RMIConfig
2014-12-30 20:42:34.539 INFO  [http-bio-8080-exec-7] AbstractConfig.java:102 ----------------------------------------------
2014-12-30 20:42:34.539 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   valid: true
2014-12-30 20:42:34.539 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   rmiName: jackrabbit.repository
2014-12-30 20:42:34.539 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   class: class org.apache.jackrabbit.j2ee.RMIConfig
2014-12-30 20:42:34.540 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   rmiUri: //localhost:1099/jackrabbit.repository
2014-12-30 20:42:34.540 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   rmiPort: 1099
2014-12-30 20:42:34.540 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   rmiEnabled: true
2014-12-30 20:42:34.540 INFO  [http-bio-8080-exec-7] AbstractConfig.java:106   rmiHost: localhost
2014-12-30 20:42:34.540 INFO  [http-bio-8080-exec-7] AbstractConfig.java:108 ----------------------------------------------
2014-12-30 20:42:34.810 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:258 Starting repository...
2014-12-30 20:42:34.816 INFO  [http-bio-8080-exec-7] LocalFileSystem.java:166 LocalFileSystem initialized at path D:\JournalDev\eclipse\jackrabbit\repository
2014-12-30 20:42:35.011 INFO  [http-bio-8080-exec-7] NodeTypeRegistry.java:841 no custom node type definitions found
2014-12-30 20:42:35.094 INFO  [http-bio-8080-exec-7] LocalFileSystem.java:166 LocalFileSystem initialized at path D:\JournalDev\eclipse\jackrabbit\version
2014-12-30 20:42:44.290 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:2034 initializing workspace 'default'...
2014-12-30 20:42:44.291 INFO  [http-bio-8080-exec-7] LocalFileSystem.java:166 LocalFileSystem initialized at path D:\JournalDev\eclipse\jackrabbit\workspaces\default
2014-12-30 20:42:52.648 INFO  [http-bio-8080-exec-7] ClusterNode.java:432 not started: namespace operation ignored.
2014-12-30 20:42:52.657 INFO  [http-bio-8080-exec-7] ClusterNode.java:432 not started: namespace operation ignored.
2014-12-30 20:42:52.663 INFO  [http-bio-8080-exec-7] ClusterNode.java:432 not started: namespace operation ignored.
2014-12-30 20:42:53.948 INFO  [http-bio-8080-exec-7] MultiIndex.java:1221 indexing... /jcr:system/jcr:nodeTypes/rep:Token/jcr:propertyDefinition (100)
2014-12-30 20:42:54.451 INFO  [http-bio-8080-exec-7] SearchIndex.java:602 Index initialized: D:\JournalDev\eclipse\jackrabbit/repository/index Version: 3
2014-12-30 20:42:54.537 INFO  [http-bio-8080-exec-7] SearchIndex.java:602 Index initialized: D:\JournalDev\eclipse\jackrabbit\workspaces\default/index Version: 3
2014-12-30 20:42:54.537 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:2038 workspace 'default' initialized
2014-12-30 20:42:54.544 INFO  [http-bio-8080-exec-7] ClusterNode.java:1064 not started: namespace operation ignored.
2014-12-30 20:42:54.545 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:546 created system workspace: security
2014-12-30 20:42:54.552 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:454 SecurityManager = class org.apache.jackrabbit.core.DefaultSecurityManager
2014-12-30 20:42:54.553 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:2034 initializing workspace 'security'...
2014-12-30 20:42:54.553 INFO  [http-bio-8080-exec-7] LocalFileSystem.java:166 LocalFileSystem initialized at path D:\JournalDev\eclipse\jackrabbit\workspaces\security
2014-12-30 20:43:02.458 INFO  [http-bio-8080-exec-7] SearchIndex.java:602 Index initialized: D:\JournalDev\eclipse\jackrabbit\workspaces\security/index Version: 3
2014-12-30 20:43:02.459 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:2038 workspace 'security' initialized
2014-12-30 20:43:02.470 INFO  [http-bio-8080-exec-7] DefaultSecurityManager.java:173 init: use Repository Login-Configuration for Jackrabbit
2014-12-30 20:43:02.512 INFO  [http-bio-8080-exec-7] UserManagerImpl.java:446 Admin user does not exist.
2014-12-30 20:43:02.793 INFO  [http-bio-8080-exec-7] ClusterNode.java:631 not started: update create ignored.
2014-12-30 20:43:02.803 INFO  [http-bio-8080-exec-7] ClusterNode.java:652 not started: update prepare ignored.
2014-12-30 20:43:02.840 INFO  [http-bio-8080-exec-7] ClusterNode.java:695 not started: update commit ignored.
2014-12-30 20:43:02.857 INFO  [http-bio-8080-exec-7] UserManagerImpl.java:1010 ... created admin user with id 'admin' and default pw.
2014-12-30 20:43:02.886 INFO  [http-bio-8080-exec-7] ClusterNode.java:631 not started: update create ignored.
2014-12-30 20:43:02.887 INFO  [http-bio-8080-exec-7] ClusterNode.java:652 not started: update prepare ignored.
2014-12-30 20:43:02.915 INFO  [http-bio-8080-exec-7] ClusterNode.java:695 not started: update commit ignored.
2014-12-30 20:43:02.918 INFO  [http-bio-8080-exec-7] DefaultSecurityManager.java:627 ... created anonymous user with id 'anonymous' ...
2014-12-30 20:43:02.967 INFO  [http-bio-8080-exec-7] RepositoryImpl.java:366 Repository started (28157ms)
2014-12-30 20:43:03.230 INFO  [http-bio-8080-exec-7] RepositoryStartupServlet.java:597 Repository bound via RMI with name: //localhost:1099/jackrabbit.repository
2014-12-30 20:43:03.234 INFO  [http-bio-8080-exec-7] RepositoryStartupServlet.java:487 Repository bound to JNDI with name: jackrabbit.repository
2014-12-30 20:43:03.234 INFO  [http-bio-8080-exec-7] RepositoryStartupServlet.java:260 RepositoryStartupServlet initialized.

Location of My Repository

  • Populate random content from Google by clicking on Populate link that’s located underneath Default Workspace at the left pane, accept all options, press on Populate ! and waiting till the process of content gathering get finished.

Populating Contents

Don’t miss the step that’s fixing the populate.jsp mentioned later. Even you may use the latest version of Jackrabbit 2.8.0 but actually this is also contained a known bug in populate page that prevents you from populating contents.

Populate Contents Jackrabbit Repository - Contents Populated

  • To ensure that you’re really populating contents into your repository, just access the following link http://localhost:8080/jackrabbit-webapp-2.8.0/repository/default/. This link is also known as WebDAV client. You may be asked for username and password while any may be fair enough. WebDAV is one of the ways that can be used for accessing the content of Repository. Later on different ways might be taken in the consideration.

List all contents

  • Follow above links to access your content into your repository just like you see in the image below. URL marked yellow has linked to PDF document.

Access PDF from your repository

Getting Started Using of JCR/JSR 170 & 283

It’s not fit to start discussing JCR/JSR 170 without mentioning the main concept of Content Repository. First of all let’s define Repository Model, a Content Repositories consists of one or more Workspaces, each of which contains a tree of items.

Basically, every item in the tree is either a node or a property, each node may have zero or more child nodes and zero or more child properties. There is a single root node per workspace, which has no parent. All other nodes have one parent. Properties have one parent and cannot have children; they are actually leaves of the tree.

Below figure depict you how the repository would look like:

Alfresco - Content Repository Model
Here’s detailed explanation for the figure mentioned above:

  • For every Workspace, there’s only one root node.
  • Per every root node, there’s a lot of nodes as a children.
  • Per every node, there’s a nodes or properties.
  • Nodes may or may not have a child while properties shouldn’t ever have children.

Now, let’s see the API basics for the JCR/JSR 170 and how can we leverage it connecting Jackrabbit content repository. Here’s below main highlights about JCR / JSR 170/283 API:

  • The javax.jcr.Repository class represents the reference of the whole Repository that you may connect. Actually this is the entry point for the Repository.
  • Calling of getRootNode() against your Repository instance will return back to you the Root node for default workspace.
  • You may get all properties for a node through using of node.getProperties().
  • You may get all node’s children by calling of node.getNodes().
  • You may get specific property for a specific node just like get binary data for which the node is created.

Actually, there are a lot of things you may take care of when it comes to discuss Content Repository concept. Data management, Query facility, Transactions and much more might be subjects for next coming tutorials that absolutely will provide you something comprehensive rather focusing on the integration that happened here.

Accessing Repository – Local Access / JNDI

Even though Jackrabbit has defined its Repository through Dummy JNDI directory local to the jackrabbit-webapp-2.8.0 but actually this resource isn’t Global JNDI resource since you can’t define a ResourceLink inside your Web Application to get accessed this defined Repository instance.

Actually you may refer to good article had written by Pankaj for getting JNDI resources defined and to know what the difference between local resources and global resources as the process of defining Jackrabbit Repository Global resource may require you knowing a lot of information relevant for this field.

Following below steps required for defining Jackrabbit Repository and get it accessed after then through a simple Servlet:

  • Make sure you’re able of seeing the Repository contents through WebDAV as stated earlier. Through accessing http://localhost:8080/jackrabbit-webapp-2.8.0/repository/default/ URL will retrieve all contents by calling local defined JNDI and by that you will be make sure that you have installed your Repository correctly.
  • Shut down your Server (Apache Tomcat 7) and make sure you’re removed deployed Jackrabbit-webapp-2.8.0 either that exploded folder or WAR copy to prevent this Jackrabbit Web application from locking the Repository.
  • Open your server.xml file that is located beneath of conf folder that exist under your Apache Server home.

Apache Tomcat - Server Configuration XML File

  • Add your Repository Global Repository Resource into your GlobalNamingResources to be look like below:

server.xml


  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>

	<Resource configFilePath="D:\JournalDev\eclipse\jackrabbit\repository.xml"
			  factory="org.apache.jackrabbit.core.jndi.BindableRepositoryFactory"
			  name="jackrabbit.repository" repHomeDir="D:\JournalDev\eclipse\jackrabbit"
			  type="javax.jcr.Repository"
			  auth="Container" />
  </GlobalNamingResources>
  • Copy all JARs from Jackrabbit-webapp-2.8.0\WEB-INF\lib into Tomact’s library folder D:\Apache Api\apache-tomcat-7.0.35\lib. This exactly will make creation of Repository JNDI global resource possible.

Apache Tomcat - Copying All Relevant JARs

  • Create Maven web application.
  • Create simple Servlet to acquire JCR Repository instance by using JNDI like below:

LocalAccess.java


package com.journaldev.web;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

import javax.jcr.LoginException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.users.MemoryUserDatabase;

/**
 * Servlet implementation class LocalAccess
 */
public class LocalAccess extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * Default constructor.
     */
    public LocalAccess() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {

			// Acquire initial context
			InitialContext context = new InitialContext();

			// Print out context reference
			System.out.println(context);

			// Access environment context
			Context envCtx = (Context)context.lookup("java:comp/env");

			// Lookup JNDI local resource
			MemoryUserDatabase memoryDB = (MemoryUserDatabase)
					  envCtx.lookup("jdbc/MyDB");

			// Print out the memoryUserDatabase reference
			System.out.println(memoryDB);

			// Lookup Global JNDI for JCR Repository
			Repository repository = (Repository) envCtx.lookup("jackrabbit.repository");

			// Print out reference variable
			System.out.println(repository);

			// Get Repository session by loggin into
			Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));

			response.getWriter().print("You're logged in successfully ::");
			// Print out the root node
			System.out.println(session.getRootNode());

			response.getWriter().print("Repository Acquired :: Root Node Identifier Is :: "+session.getRootNode().getIdentifier()+" & Its Path Is :: "+session.getRootNode().getPath());

		} catch (NamingException e) {
			e.printStackTrace();
		} catch (LoginException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RepositoryException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
  • You may define as many resources as you wish inside your web.xml, but you may not be able of defining some of them due to resources creation limitation and requirements. For this purpose, Tomcat has defined the context.xml file that should be defined under webapp/META-INF/context.xml to take its effect. Following below the context file of LocalAccess application.

context.xml


<Context path="/LocalAccess" docBase="${catalina.home}/webapps/LocalAccess" crossContext="true"
			privileged="true" antiResourceLocking="false" antiJARLocking="false">
	<GlobalNamingResources>
		<Resource name="jdbc/MyDB" auth="Container"
		            type="org.apache.catalina.UserDatabase"
		     			description="Memory Database"
		     			factory="org.apache.catalina.users.MemoryUserDatabaseFactory"/>
	</GlobalNamingResources>
	<ResourceLink name="jdbc/MyDB"
            global="jdbc/MyDB"
            	type="org.apache.catalina.UserDatabase"
            		description="Memory Database"
		     			factory="org.apache.catalina.users.MemoryUserDatabaseFactory"/>
	<ResourceLink name="jackrabbit.repository"
            global="jackrabbit.repository"
		        auth="Container"
		        	type="javax.jcr.Repository"/>
</Context>

For now, you made a lot of steps and most of them need to be clarified for you. Here’s detailed explanation for codes listed above:

  • By referring for Pankaj tutorial, you may able of knowing to which these resources mentioned are referred. We have one two global resources defined in server.xml and three resources defined locally (In context.xml which relevant for LocalAccess).
  • You may not be able of accessing the Repository global JNDI resource that had defined in server.xml if you’re not provided the resource link for it inside your localAccess’s context file.
  • According for Apache Tomcat, it’s not recommended to use server.xml to define your contexts and/or global resources as this file isn’t got reflected but when the Tomcat server has restarted.
  • It’s so elegant for you to use local context files for much cases faced.
  • As exceptional case, you may not be able of seeing your Repository initialized in case you defined it locally as such you see its global definition above within server.xml.
  • Apache Tomcat provides a JNDI InitialContext implementation instance for each Web Application/Context running under it. As such you may use InitialContext ctx = new InitialContext() safely.
  • You may notice that we’ve used the Jackrabbit-webapp.2.8.0 to initialize Jackrabbit Repository and after that we omitted it. If you’re defining your Global JNDI resource while still Jackrabbit-webapp.2.8.0 is still defined under Tomcat’s webapps your Jackrabbit-webapp.2.8.0 will be failed as the Global JNDI resource has already locked the Repository.

Now, look at the expected result right below here:

Acquiring Repository JNDI And Logged Into Successfully Find here Acquiring Jackrabbit Repository By JNDI Example.

Accessing Repository – Local Access / Servlet Context

This type of accessing Jackrabbit Repository is so easy in compare of previous JNDI resource. Here, all what you need is just to configure your context to support cross context and hence you become able of accessing Jackrabbit Repository by acquiring it from Jackrabbit-webapp-2.8.0 context attributes.

If you were print out all defined attributes inside Jackrabbit-webapp-2.8.0 you will see the following result:

LocalAccess-Context Attributes


javax.jcr.Repository
jackrabbit.webdav.jcr.resourcepath
org.apache.tomcat.InstanceManager
org.apache.catalina.jsp_classpath
repository.access.servlet
jackrabbit.webdav.simple.resourcepath
org.apache.tomcat.util.scan.MergedWebXml
javax.servlet.context.tempdir
org.apache.catalina.resources
org.apache.tomcat.JarScanner
org.apache.jasper.compiler.TldLocationsCache
repository.startup.servet

According for previous result, there’s an attribute named javax.jrc.Repository that bounded into real Jackrabbit Repository instance. To use this methodology you may follow below steps:

  • Create New Maven Web Application. We assumed that you create LocalAccess-Context.
  • Create LocalAccess Servlet like below and use the ServletContext to access Repository instance that’s defined in Jackrabbit-webapp-2.8.0.

LocalAccess.java


package com.journaldev.web;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

import javax.jcr.LoginException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.users.MemoryUserDatabase;

/**
 * Servlet implementation class LocalAccess
 */
public class LocalAccess extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * Default constructor.
     */
    public LocalAccess() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			// Acquire ServletContext
			ServletContext context = this.getServletContext();

			// Asking ServletContext get you Jackrabbit context
			ServletContext jackrabbitCtx = context.getContext("/jackrabbit-webapp-2.8.0");

			// Get all attributes
			Enumeration<String> enums = jackrabbitCtx.getAttributeNames();

			for(;enums.hasMoreElements();){
				System.out.println(enums.nextElement());
			}

			Repository repository = (Repository)jackrabbitCtx.getAttribute(Repository.class.getName());

			// Print out reference variable
			System.out.println(repository);

			// Get Repository session by loggin into
			Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));

			response.getWriter().print("You're logged in successfully ::");
			// Print out the root node
			System.out.println(session.getRootNode());

			response.getWriter().print("Repository Acquired :: Root Node Identifier Is :: "+session.getRootNode().getIdentifier()+" & Its Path Is :: "+session.getRootNode().getPath());
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

}

Here’s below detailed explanation for the code listed above:

  • We’ve assumed that you were provided context.xml file with attribute crossContext="true". If you weren’t provided it you’ll likely get an exception of cause NullPointerException since there’s no instance is returned from context.getContext("/jackrabbit-webapp-2.8.0").
  • Jackrabbit-webapp-2.8.0 has defined Jackrabbit Repository reference as attribute.
  • Make sure you have Jackrabbit-webapp-2.8.0 up & running.

Acquiring Repository Context Attribute And Logged Into Successfully Find here Acquiring Jackrabbit Repository By Context Attribute Example.

Accessing Repository – Local Access / JCR-Servlet

This way of Repository access isn’t variant from this old one that uses the Jackrabbit-webapp-2.8.0 context. The difference here is that you’re now using a new Maven library provided by Jackrabbit to create a Repository from any HttpServlet that has javax.jcr.Repositoryinstance inside its context.

To use this methodology, following below steps for that:

  • Create Maven Web Application.
  • Create a Servlet inside your Application and make it seems like below:

LocalAccess.java


package com.journaldev.web;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

import javax.jcr.LoginException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.users.MemoryUserDatabase;
import org.apache.jackrabbit.servlet.ServletRepository;

/**
 * Servlet implementation class LocalAccess
 */
public class LocalAccess extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * Default constructor.
     */
    public LocalAccess() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {

			// Acquire ServletContext
			ServletContext context = this.getServletContext();

			// Asking ServletContext get you Jackrabbit context
			ServletContext jackrabbitCtx = context.getContext("/jackrabbit-webapp-2.8.0");

			// Create Repository through using of ServletRepository
			Repository repository = new ServletRepository((HttpServlet)jackrabbitCtx.getAttribute("repository.access.servlet"));

			// Print out reference variable
			System.out.println(repository);

			// Get Repository session by loggin into
			Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));

			response.getWriter().print("You're logged in successfully ::");
			// Print out the root node
			System.out.println(session.getRootNode());

			response.getWriter().print("Repository Acquired :: Root Node Identifier Is :: "+session.getRootNode().getIdentifier()+" & Its Path Is :: "+session.getRootNode().getPath());
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

}

Here’s below detailed explanation for the code listed above:

  • We added jackrabbit-jcr-servlet Maven library into you project dependencies.
  • We’ve acquired Jackrabbit Servlet context just like we did in previously.
  • We’ve get HttpServlet reference for repository.access.servlet that’s defined within Jackrabbit context.
  • Pass Jackrabbit acquired Servlet into ServletRepository and the later will be able of recognizing the Repository within passed Servlet and it will return for you an instance of Repository.
  • Make sure you have Jackrabbit-webapp-2.8.0 up & running.

Acquiring Repository From JCR Servlet Library And Logged Into Successfully

Find here Acquiring Jackrabbit Repository By JCR Servlet Example.

Accessing Repository – Remote Access / RMI

All of previous methodologies were served being Jackrabbit Repository has deployed on the same machine just like your consumer applications. But what if you want to access your Repository from totally different Virtual Machine.

The solution is to use RMI registry either through using it directly or by referencing it through HTTP protocol. Following below steps required for doing that:

  • Create Maven Web Application.
  • Add jackrabbit-jcr-rmi dependency into your Pom file.
  • Create Simple Servlet the looks like below:

RemoteAccess.java


package com.journaldev.web;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.users.MemoryUserDatabase;
import org.apache.jackrabbit.rmi.repository.RMIRemoteRepository;
import org.apache.jackrabbit.rmi.repository.URLRemoteRepository;

/**
 * Servlet implementation class LocalAccess
 */
public class RemoteAccess extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * Default constructor.
     */
    public RemoteAccess() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			// Acquiring Repository using RMI Registry
			Repository repository =
				    new RMIRemoteRepository("//localhost/jackrabbit.repository");

			response.getWriter().print("Repository Is Acquired By Using RMI Registry :: "+repository +"\n");
			// Acquiring Repository using direct HTTP
			Repository repo =
				    new URLRemoteRepository("http://localhost:8080/jackrabbit-webapp-2.8.0/rmi");

			response.getWriter().print("Repository Is Acquired By Using HTTP RMI Registry :: "+repo +"\n");

			// Get Repository session by loggin into
			Session rmiSession = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));

			response.getWriter().print("You're logged in successfully Using RMI :: \n");
			// Print out the root node
			System.out.println(rmiSession.getRootNode());

			response.getWriter().print("Repository Acquired :: Root Node Identifier Is :: "+rmiSession.getRootNode().getIdentifier()+" & Its Path Is :: "+rmiSession.getRootNode().getPath()+"\n");

			// Get Repository session by loggin into
			Session httpRmiSession = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));

			response.getWriter().print("You're logged in successfully Using HTTP RMI :: \n");
			// Print out the root node
			System.out.println(httpRmiSession.getRootNode());

			response.getWriter().print("Repository Acquired :: Root Node Identifier Is :: "+httpRmiSession.getRootNode().getIdentifier()+" & Its Path Is :: "+httpRmiSession.getRootNode().getPath()+"\n");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
  • Access Jackrabbit Repository through using of RMI registry. This can be happened by direct access for RMI or by accessing it through HTTP protocol. Both cases will make sure that you’re getting the Jackrabbit repository stub.
  • Make sure you have Jackrabbit-webapp-2.8.0 up & running.

Find here Repository Access Though Using of RMI Example.

Apache Pluto & Jackrabbit Integration

Regardless of the way in which you access the Jackrabbit repository and regardless of type operations that you need for which such that integration, here’s a simple Portlet that has ability to communicate with Apache Jackrabbit Content Repository through using of JCR / JSR 170/283 standard library.

Following below steps all what you need to get this achieved:

  • Make sure that you’re so familiar with Apache Pluto Portal, Create Portlet, Create Portal Page and deploy the Portlet into your Portal Page and etc. This can be found onto Apache Pluto Introduction Tutorial.
  • I’ll use RMI to get this Achieved as already Jackrabbit-webapp-2.8.0 has already deployed on Apache 7 while Apache Pluto Portal will be deployed on different Apache Tomcat instance.
  • Import your Apache Pluto Into your Eclipse just like you did in the introduction tutorial. One major modification that you need to do now is modifying server Ports to be look like below:

Apache Pluto - Configure New Ports

  • Modify tomcat-users.xml to make sure tomcat user has authenticated and authorized properly. Your file should look like what already configured in the introduction.
  • Run your Apache Pluto from your Eclipse and access the new Ports, it should work willingly.

Apache Pluto - Home Page

  • Create Maven Web Application called JCR-Integration and add all Apache Pluto accompanies files like portlet.xml and those important Pom.xml entries. This is already covered in the introduction as you may refer it from here.
  • Add both of JCR standard API & RMI dependencies into your Pom.xml file. Look file below:

pom.xml


<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>JCR-Integration</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>JCR-Integration</name>
	<url>http://maven.apache.org</url>
	<properties>
		<deployFolder>D:/ApachePluto/pluto-2.0.3/webapps</deployFolder>
	</properties>
	<dependencies>
		<!-- Java Portlet Specification V2.0 -->
		<dependency>
			<groupId>org.apache.portals</groupId>
			<artifactId>portlet-api_2.0_spec</artifactId>
			<version>1.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.4</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.7.0</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.1</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>1.7</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>1.7</version>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
			<version>1.5</version>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity-tools</artifactId>
			<version>2.0</version>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<dependency>
			<groupId>org.apache.pluto</groupId>
			<artifactId>pluto-taglib</artifactId>
			<version>1.1.7</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.32</version>
		</dependency>
		<dependency>
			<groupId>org.apache.portals.bridges</groupId>
			<artifactId>portals-bridges-perl</artifactId>
			<version>1.0.4</version>
			<exclusions>
				<exclusion>
					<groupId>org.apache.portals.jetspeed-2:</groupId>
					<artifactId>jetspeed-rewriter</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.portals.jetspeed-2</groupId>
			<artifactId>jetspeed-rewriter</artifactId>
			<version>2.1.4</version>
			<exclusions>
				<exclusion>
					<groupId>castor</groupId>
					<artifactId>castor</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>castor</groupId>
			<artifactId>castor</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.portals.bridges</groupId>
			<artifactId>portals-bridges-common</artifactId>
			<version>2.0</version>
		</dependency>
		<dependency>
			<groupId>javax.jcr</groupId>
			<artifactId>jcr</artifactId>
			<version>2.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.jackrabbit</groupId>
			<artifactId>jackrabbit-jcr-rmi</artifactId>
			<version>2.8.0</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>${project.artifactId}</finalName>
		<plugins>
			<!-- bind 'pluto2:assemble' goal to 'process-resources' lifecycle -->
			<!-- This plugin will read your portlet.xml and web.xml and injects required
				lines -->
			<plugin>
				<groupId>org.apache.portals.pluto</groupId>
				<artifactId>maven-pluto-plugin</artifactId>
				<version>2.1.0-M3</version>
				<executions>
					<execution>
						<id>generate-sources</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>assemble</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<!-- configure maven-war-plugin to use updated web.xml -->
			<!-- This plugin will make sure your WAR will contain the updated web.xml -->
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.1.1</version>
				<configuration>
					<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-antrun-plugin</artifactId>
				<executions>
					<execution>
						<id>copy</id>
						<phase>integration-test</phase>
						<configuration>
							<tasks>
								<copy file="target/${project.artifactId}.war" tofile="${deployFolder}/${project.artifactId}.war" />
							</tasks>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
					<execution>
						<id>delete</id>
						<phase>clean</phase>
						<configuration>
							<tasks>
								<delete file="${deployFolder}/${project.artifactId}.war" />
								<delete dir="${deployFolder}/${project.artifactId}" />
							</tasks>
							<detail>true</detail>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Also, you may find below a ready-made Portlet that aimed to Traverse All Universe within your Repository and expose all binary documents inside supposed directory beneath C:/files.

JCRIntegrator.java


package com.journaldev.portlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Value;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.apache.jackrabbit.rmi.repository.URLRemoteRepository;

public class JCRIntegrator extends GenericPortlet{
	private Repository repository = null;
	private Session session = null;

	{
		try {
			// Acquiring Repository using RMI Registry
			this.repository =
				    new URLRemoteRepository("http://localhost:8080/jackrabbit-webapp-2.8.0/rmi");

			System.out.println("Repository Is Acquired By Using RMI Registry :: "+repository +"\n");

			// Get Repository session by log into
			this.session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));

			System.out.println("You're logged in successfully Using RMI :: \n");
			// Print out the root node
			System.out.println(this.session.getRootNode());

			System.out.println("Repository Acquired :: Root Node Identifier Is :: "+this.session.getRootNode().getIdentifier()+
						" & Its Path Is :: "+this.session.getRootNode().getPath()+"\n");
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
		try {

			if(this.session.isLive()){
				// Get root node for the current workspace
				Node root = this.session.getRootNode();

				// Traverse node
				traverseNode(root);

				// Traverse has finished
				response.getWriter().println("Traverse whole repository has been finished :: Please review C:/files directory as it should contain all Binay documents ::");

				// Logout session
				this.session.logout();
			}
			else {
				// Login again
				this.session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
			}

		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	// Recursive traverse node
	public void traverseNode(Node node){
		try {
				// Specify whether the node has child or not
				if(node.getNodes().getSize() != 0){
					// Get child iterator
					NodeIterator iterator =  node.getNodes();

					// Loop over child and traverse them one by one
					while(iterator.hasNext()){
						Node _node = (Node)iterator.next();
						traverseNode(_node);
					}
				}
				else {
					// Print out node information
					System.out.println("Node Name :: "+node.getName()+" :: Node Path :: "+node.getPath()+" :: Node Identifier :: "+node.getIdentifier());

					// Print out properties
					System.out.println("Node Properties :: ");

					PropertyIterator iterator =  node.getProperties();

					while(iterator.hasNext()){
						// Get property
						Property property = (Property)iterator.next();

						// Get specific property like jcr:data
						if(node.getProperty("jcr:data") != null){
							// Get binary stream
							InputStream content = node.getProperty("jcr:data").getBinary().getStream();

							// Create bytes array by number of available bytes
							byte [] bytes = new byte [content.available()];

							// Read contents
							content.read(bytes,0,content.available());

							// Create file, we've assumed that we will persist all binary data into C:/files
							File file = new File("c:/files/"+node.getIdentifier()+node.getPath().substring(node.getPath().indexOf("."),node.getPath().indexOf(".")+4));

							// Create file output stream
							FileOutputStream wf = new FileOutputStream(file);

							// Write binary
							wf.write(bytes);
							// Flush
							wf.flush();
							// Close
							wf.close();
						}
						// Specify whether the property has multiple values or not
						if(property.isMultiple()){
							// Print out the property information
							System.out.print("Property Name :: "+property.getName()+" :: Property Type :: "+property.getType() + " :: Property Value :: ");
							for(Value value : property.getValues()){
								System.out.print("Value :: "+value);
							}
							System.out.println("\n");
						}
						else {
							// Print out the property information
							System.out.println("Property Name :: "+property.getName()+" :: Property Type :: "+property.getType() + " :: Property Value :: "+property.getValue());
						}

					}
				}
		}
		catch(Exception ex){
			ex.printStackTrace();
		}
	}

	public Repository getRepository() {
		return repository;
	}

	public void setRepository(Repository repository) {
		this.repository = repository;
	}

	public Session getSession() {
		return session;
	}

	public void setSession(Session session) {
		this.session = session;
	}

}

Here’s below detailed explanation for the code listed above:

  • Before any use for our Repository, you should be able of opening a session.
  • This session may be closed by invoking a direct logout method.
  • To ensure that certain session is opened, just invoke isLive method.
  • You may not be able of opening the session once again, but you may have the ability to use Repository object to get new session opened.
  • We’ve used Traverse recursive method that’s aimed to print out all information relevant for specific node in the Content Repository structure.
  • The node has figured out its major attributes; name, path, identifier and many more can be invoked through direct method against node object.
  • We’ve used RMI method for getting integrated with the JCR Repository system.

By accessing the URL http://localhost:8181/pluto/portal/JournalDev you will be able of seeing the following results:

Here’s below the success response for the Portlet as it inform you that the Traverse process has been finished successfully and you may see the all files located underneath mentioned directory.

Traverse Whole Repository Contents
Below, you may also find the console of the Eclipse as Traverse has printed out all information relevant of every traversed node.

Traverse Whole Repository - Print out Node Information
Also, you may find below the C:/filesdirectory that contains all binary data that are retained in the Jackrabbit Repository.

Traverse Whole Repository - All Binaries
Also, find here Apache Pluto JCR Integration Example.

Summary

Content Repository API for Java is fundamental core library that integrated these days with most of systems being used. This tutorial is a full comprehensive reference that can help you integrating your Portal with any of Content Repository that you may use.

Jackrabbit content repository is used for such purpose and Apache Pluto is our Portal provider. Contribute us by commenting below and find above all sources that you may need for your practice.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages