Author: bcarothers
Date: 2010-01-09 11:59:11 -0500 (Sat, 09 Jan 2010)
New Revision: 1567
Added:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JndiRepositoryFactory.java
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
Log:
DNA-640 JNDI-Based Deployment
Applied patch adds a standalone JNDI factory for the JcrEngine class that exposes JCR
repositories. Multiple JCR repositories can be exposed by the same engine by creating
successive JNDI references. Only one JcrEngine will be started/loaded.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2010-01-09 11:58:01 UTC
(rev 1566)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2010-01-09 16:59:11 UTC
(rev 1567)
@@ -32,6 +32,12 @@
@Immutable
public final class JcrI18n {
+ public static I18n engineStarting;
+ public static I18n engineStarted;
+ public static I18n couldNotStartEngine;
+ public static I18n engineStopping;
+ public static I18n engineStopped;
+
public static I18n cannotConvertValue;
public static I18n credentialsMustProvideJaasMethod;
public static I18n mustBeInPrivilegedAction;
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JndiRepositoryFactory.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JndiRepositoryFactory.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JndiRepositoryFactory.java 2010-01-09
16:59:11 UTC (rev 1567)
@@ -0,0 +1,181 @@
+package org.jboss.dna.jcr;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.concurrent.TimeUnit;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamespaceChangeListener;
+import javax.naming.event.NamingEvent;
+import javax.naming.event.NamingExceptionEvent;
+import javax.naming.spi.ObjectFactory;
+import org.jboss.dna.common.collection.Problem;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.util.Logger;
+import org.xml.sax.SAXException;
+
+/**
+ * The {@code JndiRepositoryFactory} class provides a means of initializing and accessing
{@link Repository repositories} in a
+ * JNDI tree. <h2>Example JNDI Configurations</h2> <h3>Tomcat
5.5</h3>
+ * <p>
+ * The following configuration can be added to added to server.xml in Tomcat 5.5 to
initialize a {@code JcrRepository} and add it
+ * to the JNDI tree.
+ *
+ * <pre>
+ * <GlobalNamingResources>
+ * <!-- Other configuration omitted -->
+ * <Resource name="jcr/local" auth="Container"
+ * type="javax.jcr.Repository"
+ * factory="org.jboss.dna.jcr.JndiRepositoryFactory"
+ * configFile="/tck/default/configRepository.xml"
+ * repositoryName="Test Repository Source"
+ * />
+ * </GlobalNamingResources>
+ * </pre>
+ *
+ * This will create a repository loaded from the resource
"/tck/default/configRepository.xml" (which must be accessible
+ * through the classpath) and return the JCR repository named "Test Repository
Source". The name of the repository is
+ * important as a single configuration file may contain configuration information for
many JCR repositories.
+ * </p>
+ */
+public class JndiRepositoryFactory implements ObjectFactory {
+
+ private static final String CONFIG_FILE = "configFile";
+ private static final String REPOSITORY_NAME = "repositoryName";
+
+ private static JcrEngine engine;
+ protected static final Logger log = Logger.getLogger(JndiRepositoryFactory.class);
+
+ /**
+ * {@link JcrConfiguration#loadFrom(java.io.InputStream) Initializes} and {@link
JcrEngine#start() starts} the {@code
+ * JcrEngine} managed by this factory.
+ *
+ * @param configResourceName the fully-qualified name of the resource containing the
configuration information for the {@code
+ * JcrEngine}
+ * @throws IOException if there is an error or problem reading the configuration
resource at the supplied path
+ * @throws SAXException if the contents of the configuration resource are not valid
XML
+ * @throws RepositoryException if the {@link JcrEngine#start() JcrEngine could not be
started}
+ * @see JcrConfiguration#loadFrom(java.io.InputStream)
+ * @see Class#getResourceAsStream(String)
+ */
+ private static synchronized void initializeEngine( String configResourceName )
+ throws IOException, SAXException, RepositoryException {
+ if (engine != null) return;
+
+ log.info(JcrI18n.engineStarting);
+ long start = System.currentTimeMillis();
+
+ JcrConfiguration config = new JcrConfiguration();
+ engine =
config.loadFrom(JndiRepositoryFactory.class.getResourceAsStream(configResourceName)).build();
+ engine.start();
+
+ Problems problems = engine.getProblems();
+ for (Problem problem : problems) {
+ switch (problem.getStatus()) {
+ case ERROR:
+ log.error(problem.getThrowable(), problem.getMessage(),
problem.getParameters());
+ break;
+ case WARNING:
+ log.warn(problem.getThrowable(), problem.getMessage(),
problem.getParameters());
+ break;
+ case INFO:
+ log.info(problem.getThrowable(), problem.getMessage(),
problem.getParameters());
+ break;
+ }
+ }
+
+ if (problems.hasErrors()) {
+ throw new RepositoryException(JcrI18n.couldNotStartEngine.text());
+ }
+ log.info(JcrI18n.engineStarted, (System.currentTimeMillis() - start));
+ }
+
+ /**
+ * Creates an {@code JcrRepository} using the reference information specified.
+ * <p>
+ * This method first attempts to convert the {@code obj} parameter into a {@link
Reference reference to JNDI configuration
+ * information}. If that is successful, a {@link JcrEngine} will be created (if not
previously created by a call to this
+ * method) and it will be configured from the resource at the location specified by
the {@code configFile} key in the
+ * reference. After the configuration is successful, the {@link
JcrEngine#getRepository(String) JcrEngine will be queried} for
+ * the repository with the name specified by the value of the @{code repositoryName}
key in the reference.
+ * </p>
+ *
+ * @param obj the reference to the JNDI configuration information; must be a non-null
instance of {@link Reference}
+ * @param name ignored
+ * @param nameCtx ignored
+ * @param environment ignored
+ * @throws IOException if there is an error or problem reading the configuration
resource at the supplied path
+ * @throws SAXException if the contents of the configuration resource are not valid
XML
+ * @throws NamingException if there is an error registering the namespace listener
+ * @throws RepositoryException if the {@link JcrEngine#start() JcrEngine could not be
started}, the named repository does not
+ * exist in the given configuration resource, or the named repository could
not be created
+ */
+ @Override
+ public JcrRepository getObjectInstance( Object obj,
+ Name name,
+ Context nameCtx,
+ Hashtable<?, ?> environment )
+ throws IOException, SAXException, RepositoryException, NamingException {
+ if (!(obj instanceof Reference)) return null;
+
+ Reference ref = (Reference)obj;
+
+ if (engine == null) {
+ RefAddr configFile = ref.get(CONFIG_FILE);
+ assert configFile != null;
+
+ initializeEngine(configFile.getContent().toString());
+
+ if (nameCtx instanceof EventContext) {
+ EventContext evtCtx = (EventContext)nameCtx;
+
+ NamespaceChangeListener listener = new NamespaceChangeListener() {
+
+ public void namingExceptionThrown( NamingExceptionEvent evt ) {
+ evt.getException().printStackTrace();
+ }
+
+ public void objectAdded( NamingEvent evt ) {
+ }
+
+ public void objectRemoved( NamingEvent evt ) {
+ Object oldObject = evt.getOldBinding().getObject();
+ if (!(oldObject instanceof JcrEngine)) return;
+
+ JcrEngine engine = (JcrEngine)oldObject;
+
+ log.info(JcrI18n.engineStopping);
+ long start = System.currentTimeMillis();
+ engine.shutdown();
+ try {
+ engine.awaitTermination(30, TimeUnit.SECONDS);
+ log.info(JcrI18n.engineStopped, (System.currentTimeMillis() -
start));
+ } catch (InterruptedException ie) {
+ // Thread.interrupted();
+ }
+ }
+
+ public void objectRenamed( NamingEvent evt ) {
+ }
+
+ };
+
+ evtCtx.addNamingListener(name, EventContext.OBJECT_SCOPE, listener);
+ }
+ }
+
+ assert engine != null;
+
+ RefAddr repositoryName = ref.get(REPOSITORY_NAME);
+ assert repositoryName != null;
+
+ return engine.getRepository(repositoryName.getContent().toString());
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JndiRepositoryFactory.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2010-01-09
11:58:01 UTC (rev 1566)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2010-01-09
16:59:11 UTC (rev 1567)
@@ -21,6 +21,13 @@
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
#
+
+engineStarting = JcrEngine starting...
+engineStarted = JcrEngine started in {0} ms
+couldNotStartEngine = Could not start the JcrEngine
+engineStopping = JcrEngine stopping...
+engineStopped = JcrEngine stopped in {0} ms
+
cannotConvertValue = Cannot convert {0} value to {1}
credentialsMustProvideJaasMethod = The Credentials class "{0}" must implement
"public LoginContext getLoginContext();", be an instance of
"javax.jcr.SimpleCredentials", or be an instance of
"org.jboss.dna.jcr.SecurityContextCredentials"
mustBeInPrivilegedAction=login() can only be called successfully from within a
java.security.PrivilegedAction or when the ANONYMOUS_USER_ROLES repository option is set