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:Jackrabbitjackrabbit-2.8.0
. - Open your
jackrabbit-webapp
and modifypopulate.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
https://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="https://www.journaldev.com/5109/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 = "https://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", "https://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 yourjackrabbit-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:
- Deploy Jackrabbit Web Application from your
jackrabbit-webapp
project. - Download JCR 2.0 API JAR from here into your Apache Tomcat lib.
- Run your Tomcat Server from your Eclipse.
- Access
https://localhost:8080/jackrabbit-webapp-2.8.0/
to open the home page of Apache Jackrabbit.
- Create new repository by clicking on Create Content Repository. Your repository home directory will be jackrabbit just like you see above.
- 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:JournalDeveclipsejackrabbit
.
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: jackrabbitrepository.xml
2014-12-30 20:42:34.505 INFO [http-bio-8080-exec-7] Installer.java:221 Creating new bootstrap properties: jackrabbitbootstrap.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: [email protected]
2014-12-30 20:42:34.536 INFO [http-bio-8080-exec-7] AbstractConfig.java:106 repositoryConfig: jackrabbitrepository.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: [email protected]
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=https://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:JournalDeveclipsejackrabbitrepository
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:JournalDeveclipsejackrabbitversion
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:JournalDeveclipsejackrabbitworkspacesdefault
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:JournalDeveclipsejackrabbit/repository/index Version: 3
2014-12-30 20:42:54.537 INFO [http-bio-8080-exec-7] SearchIndex.java:602 Index initialized: D:JournalDeveclipsejackrabbitworkspacesdefault/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:JournalDeveclipsejackrabbitworkspacessecurity
2014-12-30 20:43:02.458 INFO [http-bio-8080-exec-7] SearchIndex.java:602 Index initialized: D:JournalDeveclipsejackrabbitworkspacessecurity/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.
- 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.
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.
- To ensure that you’re really populating contents into your repository, just access the following link
https://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.
- 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.
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:
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
https://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.
- 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:JournalDeveclipsejackrabbitrepository.xml"
factory="org.apache.jackrabbit.core.jndi.BindableRepositoryFactory"
name="jackrabbit.repository" repHomeDir="D:JournalDeveclipsejackrabbit"
type="javax.jcr.Repository"
auth="Container" />
</GlobalNamingResources>
- Copy all JARs from Jackrabbit-webapp-2.8.0WEB-INFlib into Tomact’s library folder
D:Apache Apiapache-tomcat-7.0.35lib
. This exactly will make creation of Repository JNDI global resource possible.
- 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 thecontext.xml
file that should be defined underwebapp/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 (Incontext.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 stillJackrabbit-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:
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 attributecrossContext="true"
. If you weren’t provided it you’ll likely get an exception of cause NullPointerException since there’s no instance is returned fromcontext.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.
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.Repository
instance 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.
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("https://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:
- 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.
- 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="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://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>https://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("https://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 https://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.
Below, you may also find the console of the Eclipse as Traverse has printed out all information relevant of every traversed node.
Also, you may find below the C:/files
directory that contains all binary data that are retained in the Jackrabbit Repository.
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.