You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2005/12/09 10:48:51 UTC

svn commit: r355430 - in /incubator/jackrabbit/trunk/jackrabbit/src: main/java/org/apache/jackrabbit/core/TransientRepository.java test/java/org/apache/jackrabbit/core/TestAll.java test/java/org/apache/jackrabbit/core/TransientRepositoryTest.java

Author: jukka
Date: Fri Dec  9 01:48:18 2005
New Revision: 355430

URL: http://svn.apache.org/viewcvs?rev=355430&view=rev
Log:
JCR-245: Added the TransientRepository utility class and an initial test case.

Added:
    incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/TransientRepository.java   (with props)
    incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TransientRepositoryTest.java   (with props)
Modified:
    incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TestAll.java

Added: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/TransientRepository.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/TransientRepository.java?rev=355430&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/TransientRepository.java (added)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/TransientRepository.java Fri Dec  9 01:48:18 2005
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.
+ */
+package org.apache.jackrabbit.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.core.config.ConfigurationException;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.log4j.Logger;
+
+/**
+ * A repository proxy that automatically initializes and shuts down the
+ * underlying repository instance when the first session is opened
+ * or the last one closed. As long as all sessions are properly closed
+ * when no longer used, this class can be used to avoid having to explicitly
+ * shut down the repository.
+ */
+public class TransientRepository implements Repository {
+
+    /**
+     * The logger instance used to log the repository and session lifecycles.
+     */
+    private static final Logger logger =
+        Logger.getLogger(TransientRepository.class);
+
+    /**
+     * Factory interface for creating {@link RepositoryImpl} instances.
+     * Used to give greater control of the repository initialization process
+     * to users of the TransientRepository class.
+     */
+    public interface RepositoryFactory {
+
+        /**
+         * Creates and intializes a repository instance. The returned instance
+         * will be used and finally shut down by the caller of this method.
+         *
+         * @return initialized repository instance
+         * @throws RepositoryException if an instance can not be created
+         */
+        RepositoryImpl getRepository() throws RepositoryException;
+
+    }
+
+    /**
+     * The repository configuration. Set in the constructor and used to
+     * initialize the repository instance when the first session is opened.
+     */
+    private final RepositoryFactory factory;
+
+    /**
+     * The initialized repository instance. Set when the first session is
+     * opened and cleared when the last one is closed.
+     */
+    private RepositoryImpl repository;
+
+    /**
+     * The set of open sessions. When no more open sessions remain, the
+     * repository instance is automatically shut down until a new session
+     * is opened.
+     */
+    private final Set sessions;
+
+    /**
+     * The static repository descriptors. The default {@link RepositoryImpl}
+     * descriptors are loaded as the static descriptors and used whenever a
+     * live repository instance is not available (no open sessions).
+     */
+    private final Properties descriptors;
+
+    /**
+     * Creates a transient repository proxy that will use the given repository
+     * factory to initialize the underlying repository instances.
+     * 
+     * @param factory repository factory
+     * @throws IOException if the static repository descriptors cannot be loaded
+     */
+    public TransientRepository(RepositoryFactory factory) throws IOException {
+        this.factory = factory;
+        this.repository = null;
+        this.sessions = new HashSet();
+        this.descriptors = new Properties();
+
+        // FIXME: The current RepositoryImpl class does not allow static
+        // access to the repository descriptors, so we need to load them
+        // directly from the underlying property file.
+        InputStream in =
+            RepositoryImpl.class.getResourceAsStream("repository.properties");
+        try {
+            descriptors.load(in);
+        } finally {
+            in.close();
+        }
+    }
+
+    /**
+     * Creates a transient repository proxy that will use the given repository
+     * configuration to initialize the underlying repository instances.
+     * 
+     * @param config repository configuration
+     * @throws IOException if the static repository descriptors cannot be loaded
+     */
+    public TransientRepository(final RepositoryConfig config)
+            throws IOException {
+        this(new RepositoryFactory() {
+            public RepositoryImpl getRepository() throws RepositoryException {
+                return RepositoryImpl.create(config);
+            }
+        });
+    }
+
+    /**
+     * Creates a transient repository proxy that will use the given repository
+     * configuration file and home directory paths to initialize the underlying
+     * repository instances.
+     * 
+     * @param config repository configuration file
+     * @param home repository home directory
+     * @throws ConfigurationException if the configuration file is invalid
+     * @throws IOException if the static repository descriptors cannot be loaded
+     */
+    public TransientRepository(String config, String home)
+            throws ConfigurationException, IOException {
+        this(RepositoryConfig.create(config, home));
+    }
+
+    /**
+     * Returns the available descriptor keys. If the underlying repository
+     * is initialized, then the call is proxied to it, otherwise the static
+     * descriptor keys are returned.
+     *
+     * @return descriptor keys
+     * @see Repository#getDescriptorKeys()
+     */
+    public synchronized String[] getDescriptorKeys() {
+        if (repository != null) {
+            return repository.getDescriptorKeys();
+        } else {
+            List keys = Collections.list(descriptors.propertyNames());
+            Collections.sort(keys);
+            return (String[]) keys.toArray(new String[keys.size()]);
+        }
+    }
+
+    /**
+     * Returns the identified repository descriptor. If the underlying
+     * repository is initialized, then the call is proxied to it, otherwise
+     * the static descriptors are used.
+     *
+     * @param key descriptor key
+     * @return descriptor value
+     * @see Repository#getDescriptor(String)
+     */
+    public synchronized String getDescriptor(String key) {
+        if (repository != null) {
+            return repository.getDescriptor(key);
+        } else {
+            return descriptors.getProperty(key);
+        }
+    }
+
+    /**
+     * Removes the given session from the set of open sessions. If no open
+     * sessions remain, then the underlying repository instance is shut down.
+     *
+     * @param session closed session
+     */
+    private synchronized void removeSession(SessionImpl session) {
+        sessions.remove(session);
+        logger.info("Session closed");
+        if (sessions.isEmpty()) {
+            // FIXME: This is an ugly hack to avoid an infinite loop when
+            // RepositoryImpl.shutdown() repeatedly calls logout() on all
+            // remaining active sessions including the one that just emitted
+            // the loggedOut() message to us!
+            repository.loggedOut(session);
+
+            logger.debug("Shutting down transient repository");
+            repository.shutdown();
+            logger.info("Transient repository shut down");
+            repository = null;
+        }
+    }
+
+    /**
+     * Logs in to the content repository. Initializes the underlying repository
+     * instance if needed. The opened session is added to the set of open
+     * sessions and a session listener is added to track when the session gets
+     * closed.
+     *
+     * @param credentials login credentials
+     * @param workspaceName workspace name
+     * @return new session
+     * @throws RepositoryException if the session could not be created
+     * @see Repository#login(Credentials,String)
+     */
+    public synchronized Session login(Credentials credentials, String workspaceName)
+            throws RepositoryException {
+        if (repository == null) {
+            logger.debug("Initializing transient repository");
+            repository = factory.getRepository();
+            logger.info("Transient repository initialized");
+        }
+
+        logger.debug("Opening a new session");
+        SessionImpl session = (SessionImpl)
+            repository.login(credentials, workspaceName);
+        sessions.add(session);
+        session.addListener(new SessionListener() {
+            
+            public void loggedOut(SessionImpl session) {
+                removeSession(session);
+            }
+            
+            public void loggingOut(SessionImpl session) {
+            }
+            
+        });
+        logger.info("Session opened");
+
+        return session;
+    }
+
+    /**
+     * Calls {@link #login(Credentials, String)} with a <code>null</code>
+     * workspace name.
+     *
+     * @param credentials login credentials
+     * @return new session
+     * @throws RepositoryException if the session could not be created
+     * @see Repository#login(Credentials)
+     */
+    public Session login(Credentials credentials) throws RepositoryException {
+        return login(credentials, null);
+    }
+
+    /**
+     * Calls {@link #login(Credentials, String)} with <code>null</code> login
+     * credentials.
+     *
+     * @param workspaceName workspace name
+     * @return new session
+     * @throws RepositoryException if the session could not be created
+     * @see Repository#login(String)
+     */
+    public Session login(String workspaceName) throws RepositoryException {
+        return login(null, workspaceName);
+    }
+
+    /**
+     * Calls {@link #login(Credentials, String)} with <code>null</code> login
+     * credentials and a <code>null</code> workspace name.
+     *
+     * @return new session
+     * @throws RepositoryException if the session could not be created
+     * @see Repository#login(Credentials)
+     */
+    public Session login() throws RepositoryException {
+        return login(null, null);
+    }
+
+}

Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/TransientRepository.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TestAll.java?rev=355430&r1=355429&r2=355430&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TestAll.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TestAll.java Fri Dec  9 01:48:18 2005
@@ -37,6 +37,7 @@
 
         //suite.addTestSuite(ConcurrencyTest.class);
         //suite.addTestSuite(ConcurrentSaveTest.class);
+        suite.addTestSuite(TransientRepositoryTest.class);
         suite.addTestSuite(XATest.class);
 
         return suite;

Added: incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TransientRepositoryTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TransientRepositoryTest.java?rev=355430&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TransientRepositoryTest.java (added)
+++ incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TransientRepositoryTest.java Fri Dec  9 01:48:18 2005
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.
+ */
+package org.apache.jackrabbit.core;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import junit.framework.TestCase;
+
+/**
+ * Test case for the {@link TransientRepository} class. Currently only the
+ * static repository descriptor access is tested due to the difficulty of
+ * setting up mock {@link RepositoryImpl} instances.
+ */
+public class TransientRepositoryTest extends TestCase {
+
+    /**
+     * The TransientRepository instance under test.
+     */
+    private Repository repository;
+
+    /**
+     * Creates the TransientRepository instance used in testing.
+     */
+    protected void setUp() throws IOException {
+        repository = new TransientRepository(new TransientRepository.RepositoryFactory() {
+                public RepositoryImpl getRepository() throws RepositoryException {
+                    throw new UnsupportedRepositoryOperationException();
+                }
+            });
+    }
+
+    /**
+     * Tests that {@link TransientRepository} returns descriptor keys
+     * even before the underlying repository has been initialized.
+     */
+    public void testGetDescriptorKeys() {
+        String[] keys = repository.getDescriptorKeys();
+        assertNotNull(keys);
+        assertTrue(keys.length > 0);
+
+        Set keySet = new HashSet();
+        Collections.addAll(keySet, keys);
+        assertTrue(keySet.contains(Repository.SPEC_NAME_DESC));
+    }
+
+    /**
+     * Tests that {@link TransientRepository} returns descriptor values
+     * even before the underlying repository has been initialized.
+     */
+    public void testGetDescriptor() {
+        String expected =
+            "Content Repository API for Java(TM) Technology Specification";
+        String actual = repository.getDescriptor(Repository.SPEC_NAME_DESC);
+        assertEquals(expected, actual);
+    }
+
+}

Propchange: incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/TransientRepositoryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native