You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2008/03/05 12:35:13 UTC
svn commit: r633823 - in /incubator/sling/trunk/jcr/base: ./
src/main/java/org/apache/sling/jcr/base/
src/main/java/org/apache/sling/jcr/base/internal/
src/main/java/org/apache/sling/jcr/base/internal/loader/
Author: fmeschbe
Date: Wed Mar 5 03:35:06 2008
New Revision: 633823
URL: http://svn.apache.org/viewvc?rev=633823&view=rev
Log:
SLING-132 Refactor repository access based on a background thread checking
for the repository constantly and providing proper API to acquire, setup,
teardown and dispose repositories.
Modified:
incubator/sling/trunk/jcr/base/pom.xml
incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java
incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/SessionPool.java
incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java
Modified: incubator/sling/trunk/jcr/base/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/base/pom.xml?rev=633823&r1=633822&r2=633823&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/base/pom.xml (original)
+++ incubator/sling/trunk/jcr/base/pom.xml Wed Mar 5 03:35:06 2008
@@ -54,6 +54,8 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
+ <!-- require fix for FELIX-506 -->
+ <version>1.0.4-SNAPSHOT</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
@@ -95,6 +97,8 @@
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-rmi</artifactId>
+ <!-- require fix for JCR-1454 -->
+ <version>1.5-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!-- OSGi Libraries -->
Modified: incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java?rev=633823&r1=633822&r2=633823&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java (original)
+++ incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java Wed Mar 5 03:35:06 2008
@@ -35,79 +35,109 @@
import org.apache.sling.jcr.base.internal.SessionPoolFactory;
import org.apache.sling.jcr.base.internal.SessionPoolManager;
import org.apache.sling.jcr.base.internal.loader.Loader;
-import org.osgi.framework.Bundle;
+import org.apache.sling.jcr.base.util.RepositoryAccessor;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.log.LogService;
-
/**
- * The <code>AbstractSlingRepository</code> is an abstract implementation of the
- * {@link SlingRepository} interface which provides core support for session
+ * The <code>AbstractSlingRepository</code> is an abstract implementation of
+ * the {@link SlingRepository} interface which provides core support for session
* pooling. Implementations of the <code>SlingRepository</code> interface may
* wish to extend this class to benefit from a default implementation.
* <p>
* Extensions of this class will have to declare the following
* <code>scr.property</code> tags to have them declared automatically in the
* respective component and metatype definitions by the maven-sling-plugin:
- *
- * <pre>
- * scr.property value="" name="defaultWorkspace"
- * scr.property value="anonymous" name="anonymous.name"
- * scr.property value="anonymous" name="anonymous.password"
- * scr.property value="admin" name="admin.name"
- * scr.property value="admin" name="admin.password"
- * scr.property value="10" type="Integer" name="pool.maxActive"
- * scr.property value="10" type="Integer" name="pool.maxIdle"
- * scr.property value="256" type="Integer" name="pool.maxActiveWait"
- * </pre>
+ *
* @scr.component
*/
-public abstract class AbstractSlingRepository
- implements SlingRepository, SynchronousBundleListener {
+public abstract class AbstractSlingRepository implements SlingRepository,
+ SynchronousBundleListener, Runnable {
+ /** @scr.property value="" */
public static final String PROPERTY_DEFAULT_WORKSPACE = "defaultWorkspace";
+ /** @scr.property valueRef="DEFAULT_ANONYMOUS_USER" */
public static final String PROPERTY_ANONYMOUS_USER = "anonymous.name";
+ /** @scr.property valueRef="DEFAULT_ANONYMOUS_PASS" */
public static final String PROPERTY_ANONYMOUS_PASS = "anonymous.password";
+ /** @scr.property valueRef="DEFAULT_ADMIN_USER" */
public static final String PROPERTY_ADMIN_USER = "admin.name";
+ /** @scr.property valueRef="DEFAULT_ADMIN_PASS" */
public static final String PROPERTY_ADMIN_PASS = "admin.password";
-
- public static final String DEFAULT_WORKSPACE = "default";
-
- public static final String DEFAULT_ANONYMOUS_USER = "anonymous";
-
- public static final String DEFAULT_ANONYMOUS_PASS = "anonymous";
-
- public static final String DEFAULT_ADMIN_USER = "admin";
-
- public static final String DEFAULT_ADMIN_PASS = "admin";
+
+ /** @scr.property valueRef="DEFAULT_POLL_ACTIVE" */
+ public static final String PROPERTY_POLL_ACTIVE = "poll.active";
+
+ /** @scr.property valueRef="DEFAULT_POLL_INACTIVE" */
+ public static final String PROPERTY_POLL_INACTIVE = "poll.inactive";
/**
* The name of the configuration parameter containing the maximum number of
* seconds to wait for the number of currently active sessions to drop be
* low the upper limit before giving up (value is "pool.maxActiveWait").
+ *
+ * @scr.property value="1" type="Integer"
*/
- public static final String PARAM_MAX_ACTIVE_SESSIONS_WAIT = "pool.maxActiveWait";
+ public static final String PROPERTY_MAX_ACTIVE_SESSIONS_WAIT = "pool.maxActiveWait";
/**
* The name of the configuration parameter containing the upper limit of the
* simultaneously active sessions (value is "pool.maxActive").
+ *
+ * @scr.property value="-1" type="Integer"
*/
- public static final String PARAM_MAX_ACTIVE_SESSIONS = "pool.maxActive";
+ public static final String PROPERTY_MAX_ACTIVE_SESSIONS = "pool.maxActive";
/**
* The name of the configuration parameter containing the upper limit of the
* currently idle sessions to keep in the pool (value is "pool.maxIdle").
+ *
+ * @scr.property value="10" type="Integer"
*/
- public static final String PARAM_MAX_IDLE_SESSIONS = "pool.maxIdle";
+ public static final String PROPERTY_MAX_IDLE_SESSIONS = "pool.maxIdle";
+
+ public static final String DEFAULT_WORKSPACE = "default";
+
+ public static final String DEFAULT_ANONYMOUS_USER = "anonymous";
+ public static final String DEFAULT_ANONYMOUS_PASS = "anonymous";
+
+ public static final String DEFAULT_ADMIN_USER = "admin";
+
+ public static final String DEFAULT_ADMIN_PASS = "admin";
+
+ /**
+ * The default value for the number of seconds to wait between two
+ * consecutive checks while the repository is active (value is 10).
+ */
+ public static final int DEFAULT_POLL_ACTIVE = 10;
+
+ /**
+ * The default value for the number of seconds to wait between two
+ * consecutive checks while the repository is not active (value is 10).
+ */
+ public static final int DEFAULT_POLL_INACTIVE = 10;
+
+ /** The minimum number of seconds allowed for any of the two poll times */
+ public static final int MIN_POLL = 2;
+
+ /** @scr.reference bind="bindLog" unbind="unbindLog" */
+ private LogService log;
+
private ComponentContext componentContext;
+ private Repository repository;
+
+ private ServiceRegistration repositoryService;
+
private String defaultWorkspace;
private String anonUser;
@@ -122,60 +152,28 @@
private Loader loader;
- protected AbstractSlingRepository() {
- }
-
- protected abstract Repository getDelegatee() throws RepositoryException;
-
- protected final SessionPoolManager getPoolManager()
- throws RepositoryException {
- if (this.poolManager == null) {
- this.poolManager = new SessionPoolManager(this.getDelegatee(), this.loader,
- this.getSessionPoolFactory());
- }
+ // the poll interval used while the repository is not active
+ private long pollTimeInActive;
- return this.poolManager;
- }
+ // the poll interval used while the repository is active
+ private long pollTimeActive;
- /**
- * @return
- */
- protected SessionPoolFactory getSessionPoolFactory() {
- @SuppressWarnings("unchecked")
- Dictionary<String, Object> properties = this.componentContext.getProperties();
- final int maxActiveSessions = this.getIntProperty(properties,
- PARAM_MAX_ACTIVE_SESSIONS);
- final int maxIdleSessions = this.getIntProperty(properties,
- PARAM_MAX_IDLE_SESSIONS);
- final int maxActiveSessionsWait = this.getIntProperty(properties,
- PARAM_MAX_ACTIVE_SESSIONS_WAIT);
- return new SessionPoolFactory() {
+ // whether the repository checker task should be active. this field
+ // is managed by the startRepositoryPinger and stopRepositoryPinger methods
+ private boolean running;
- public SessionPool createPool(final SessionPoolManager mgr, final SimpleCredentials credentials) {
- // create and configure the new pool
- final SessionPool pool = createSessionPool(mgr, credentials);
- pool.setMaxActiveSessions(maxActiveSessions);
- pool.setMaxActiveSessionsWait(maxActiveSessionsWait);
- pool.setMaxIdleSessions(maxIdleSessions);
- return pool;
- }
- };
- }
+ // the background thread constantly checking the repository
+ private Thread repositoryPinger;
- protected SessionPool createSessionPool(final SessionPoolManager mgr, final SimpleCredentials credentials) {
- final SessionPool pool = new SessionPool(mgr, credentials);
- return pool;
+ protected AbstractSlingRepository() {
}
/**
- * @see org.apache.sling.jcr.api.SlingRepository#getDefaultWorkspace()
- * Declared final to make sure the SLING-256 rule is enforced.
+ * Returns the default workspace, which may be <code>null</code> meaning
+ * to use the repository provided default workspace.
*/
public final String getDefaultWorkspace() {
- if(defaultWorkspace == null || defaultWorkspace.trim().length() == 0) {
- // SLING-256
- return null;
- }
+ // Declared final to make sure the SLING-256 rule is enforced.
return this.defaultWorkspace;
}
@@ -187,49 +185,29 @@
return this.login(null, null);
}
- /*
- * (non-Javadoc)
- *
- * @see org.apache.sling.core.jcr.SessionProvider#getAdministrationSession()
- */
public Session loginAdministrative(String workspace)
throws RepositoryException {
- SimpleCredentials sc = new SimpleCredentials(this.adminUser, this.adminPass);
+ SimpleCredentials sc = new SimpleCredentials(this.adminUser,
+ this.adminPass);
return this.login(sc, workspace);
}
- /*
- * (non-Javadoc)
- *
- * @see javax.jcr.Repository#login(javax.jcr.Credentials)
- */
public Session login(Credentials credentials) throws LoginException,
RepositoryException {
return this.login(credentials, null);
}
- /*
- * (non-Javadoc)
- *
- * @see javax.jcr.Repository#login(java.lang.String)
- */
public Session login(String workspace) throws LoginException,
NoSuchWorkspaceException, RepositoryException {
return this.login(null, workspace);
}
- /*
- * (non-Javadoc)
- *
- * @see org.apache.sling.core.jcr.SlingRepository#login(javax.jcr.Credentials,
- * java.lang.String)
- */
public Session login(Credentials credentials, String workspace)
throws LoginException, NoSuchWorkspaceException,
RepositoryException {
// if already stopped, don't retrieve a session
- if (this.componentContext == null || this.getDelegatee() == null) {
+ if (this.componentContext == null || this.getRepository() == null) {
throw new RepositoryException("Sling Repository not ready");
}
@@ -243,13 +221,14 @@
}
try {
- getLog().log(LogService.LOG_DEBUG,
- "Logging in to workspace '" + workspace + "'");
+ log(LogService.LOG_DEBUG, "login: Logging in to workspace '"
+ + workspace + "'");
return this.getPoolManager().login(credentials, workspace);
} catch (NoSuchWorkspaceException nswe) {
// if the desired workspace is the default workspace, try to create
// (but not if using the repository-supplied default workspace)
- if (workspace!=null && workspace.equals(this.getDefaultWorkspace())
+ if (workspace != null
+ && workspace.equals(this.getDefaultWorkspace())
&& this.createWorkspace(workspace)) {
return this.getPoolManager().login(credentials, workspace);
}
@@ -262,46 +241,284 @@
/*
* (non-Javadoc)
- *
+ *
* @see javax.jcr.Repository#getDescriptor(java.lang.String)
*/
public String getDescriptor(String name) {
- try {
- return this.getDelegatee().getDescriptor(name);
- } catch (RepositoryException re) {
- this.log(LogService.LOG_ERROR, "Repository not available", re);
+ Repository repo = getRepository();
+ if (repo != null) {
+ return repo.getDescriptor(name);
}
+ log(LogService.LOG_ERROR, "getDescriptor: Repository not available");
return null;
}
/*
* (non-Javadoc)
- *
+ *
* @see javax.jcr.Repository#getDescriptorKeys()
*/
public String[] getDescriptorKeys() {
- try {
- return this.getDelegatee().getDescriptorKeys();
- } catch (RepositoryException re) {
- this.log(LogService.LOG_ERROR, "Repository not available", re);
+ Repository repo = getRepository();
+ if (repo != null) {
+ return repo.getDescriptorKeys();
}
+ log(LogService.LOG_ERROR, "getDescriptorKeys: Repository not available");
return new String[0];
}
- // ---------- logging ------------------------------------------------------
+ //---------- Session Pool support -----------------------------------------
+
+ protected final SessionPoolManager getPoolManager() {
+ if (this.poolManager == null) {
+ this.poolManager = new SessionPoolManager(this.getRepository(),
+ this.loader, this.getSessionPoolFactory());
+ }
- protected abstract LogService getLog();
+ return this.poolManager;
+ }
+
+ /**
+ * @return
+ */
+ protected SessionPoolFactory getSessionPoolFactory() {
+ @SuppressWarnings("unchecked")
+ Dictionary<String, Object> properties = this.componentContext.getProperties();
+ final int maxActiveSessions = this.getIntProperty(properties,
+ PROPERTY_MAX_ACTIVE_SESSIONS);
+ final int maxIdleSessions = this.getIntProperty(properties,
+ PROPERTY_MAX_IDLE_SESSIONS);
+ final int maxActiveSessionsWait = this.getIntProperty(properties,
+ PROPERTY_MAX_ACTIVE_SESSIONS_WAIT);
+ return new SessionPoolFactory() {
+
+ public SessionPool createPool(final SessionPoolManager mgr,
+ final SimpleCredentials credentials) {
+ // create and configure the new pool
+ final SessionPool pool = createSessionPool(mgr, credentials);
+ pool.setMaxActiveSessions(maxActiveSessions);
+ pool.setMaxActiveSessionsWait(maxActiveSessionsWait);
+ pool.setMaxIdleSessions(maxIdleSessions);
+ return pool;
+ }
+ };
+ }
+
+ protected SessionPool createSessionPool(final SessionPoolManager mgr,
+ final SimpleCredentials credentials) {
+ final SessionPool pool = new SessionPool(mgr, credentials);
+ return pool;
+ }
+
+ // ---------- logging ------------------------------------------------------
protected void log(int level, String message) {
this.log(level, message, null);
}
protected void log(int level, String message, Throwable t) {
- LogService log = this.getLog();
+ LogService log = this.log;
if (log != null) {
- log.log(this.componentContext.getServiceReference(), level, message, t);
+ log.log(this.componentContext.getServiceReference(), level,
+ message, t);
+ }
+ }
+
+ // ---------- Repository Access -------------------------------------------
+
+ /**
+ * Acquires the repository by calling the
+ * {@link org.apache.sling.jcr.base.util.RepositoryAccessor#getRepositoryFromURL(String)}
+ * with the value of the
+ * {@link org.apache.sling.jcr.base.util.RepositoryAccessor#REPOSITORY_URL_OVERRIDE_PROPERTY}
+ * framework or configuration property. If the property exists and a
+ * repository can be accessed using this property, that repository is
+ * returned. Otherwise <code>null</code> is returned.
+ * <p>
+ * Extensions of this class may overwrite this method with implementation
+ * specific acquisition semantics and may call this base class method or not
+ * as the implementation sees fit.
+ * <p>
+ * This method does not throw any <code>Throwable</code> but instead just
+ * returns <code>null</code> if not repository is available. Any problems
+ * trying to acquire the repository must be caught and logged as
+ * appropriate.
+ *
+ * @return The acquired JCR <code>Repository</code> or <code>null</code>
+ * if not repository can be acquired.
+ */
+ protected Repository acquireRepository() {
+ // if the environment provides a repository override URL, other settings
+ // are ignored
+ String overrideUrl = (String) componentContext.getProperties().get(
+ RepositoryAccessor.REPOSITORY_URL_OVERRIDE_PROPERTY);
+ if (overrideUrl == null) {
+ overrideUrl = componentContext.getBundleContext().getProperty(
+ RepositoryAccessor.REPOSITORY_URL_OVERRIDE_PROPERTY);
+ }
+
+ if (overrideUrl != null && overrideUrl.length() > 0) {
+ log(LogService.LOG_INFO,
+ "acquireRepository: Will not use embedded repository due to property "
+ + RepositoryAccessor.REPOSITORY_URL_OVERRIDE_PROPERTY + "="
+ + overrideUrl + ", acquiring repository using that URL");
+ return new RepositoryAccessor().getRepositoryFromURL(overrideUrl);
+ }
+
+ log(LogService.LOG_DEBUG,
+ "acquireRepository: No existing repository to access");
+ return null;
+ }
+
+ /**
+ * This method is called after a repository has been acquired by
+ * {@link #acquireRepository()} but before the repository is registered as a
+ * service.
+ * <p>
+ * Implementations may overwrite this method but MUST call this base class
+ * implementation first.
+ *
+ * @param repository The JCR <code>Repository</code> to setup.
+ */
+ protected void setupRepository(Repository repository) {
+ BundleContext bundleContext = componentContext.getBundleContext();
+ this.loader = new Loader(this, bundleContext.getBundles());
+ }
+
+ /**
+ * Registers this component as an OSGi service with type
+ * <code>javax.jcr.Repository</code> and
+ * <code>org.apache.sling.jcr.api.SlingRepository</code> using the
+ * component properties as service registration properties.
+ * <p>
+ * This method may be overwritten to register the component with different
+ * types.
+ *
+ * @return The OSGi <code>ServiceRegistration</code> object representing
+ * the registered service.
+ */
+ protected ServiceRegistration registerService() {
+ @SuppressWarnings("unchecked")
+ Dictionary<String, Object> props = componentContext.getProperties();
+ String[] interfaces = new String[] { SlingRepository.class.getName(),
+ Repository.class.getName() };
+
+ return componentContext.getBundleContext().registerService(interfaces,
+ this, props);
+ }
+
+ /**
+ * Returns the repository underlying this instance or <code>null</code> if
+ * no repository is currently being available.
+ */
+ protected Repository getRepository() {
+ return repository;
+ }
+
+ /**
+ * Checks that the given <code>repository</code> is still available. This
+ * implementation tries to get the <code>Repository.SPEC_NAME_DESC</code>
+ * descriptor from the repository and returns <code>true</code> if the
+ * returned value is not <code>null</code>.
+ * <p>
+ * Extensions of this class may overwrite this method to implement different
+ * access checks. The contract of this method must be obeyed, though in a
+ * sense, the <code>true</code> must only be returned if
+ * <code>repository</code> is actually usable.
+ *
+ * @param repository The JCR <code>Repository</code> to check for
+ * availability.
+ * @return <code>true</code> if <code>repository</code> is not
+ * <code>null</code> and accessible.
+ */
+ protected boolean pingRepository(Repository repository) {
+ if (repository != null) {
+ try {
+ return repository.getDescriptor(Repository.SPEC_NAME_DESC) != null;
+ } catch (Throwable t) {
+ log(LogService.LOG_DEBUG, "pingRepository: Repository "
+ + repository + " does not seem to be available any more", t);
+ }
+ }
+
+ // fall back to unavailable
+ return false;
+ }
+
+ /**
+ * Unregisters the service represented by the
+ * <code>serviceRegistration</code>.
+ * <p>
+ * This method may be overwritten by extensions of this class as long as it
+ * is made sure, the given service registration is unregistered.
+ */
+ protected void unregisterService(ServiceRegistration serviceRegistration) {
+ serviceRegistration.unregister();
+ }
+
+ /**
+ * Performs any cleanups before the repository is actually disposed off by
+ * the {@link #disposeRepository(Repository)} method.
+ * <p>
+ * This method is meant for cleanup tasks before the repository is actually
+ * disposed off. Extensions of this class may overwrite but must call this
+ * base class implementation.
+ *
+ * @param repository
+ */
+ protected void tearDown(Repository repository) {
+
+ if (this.poolManager != null) {
+ this.poolManager.dispose();
+ this.poolManager = null;
+ }
+
+ if (this.loader != null) {
+ this.loader.dispose();
+ this.loader = null;
+ }
+ }
+
+ /**
+ * Disposes off the given <code>repository</code>. This base class
+ * implementation does nothing. Extensions should overwrite if any special
+ * disposal operation is required.
+ *
+ * @param repository
+ */
+ protected void disposeRepository(Repository repository) {
+ // nothing to do here ...
+ }
+
+ //---------- SynchronousBundleListener ------------------------------------
+
+ /**
+ * Loads and unloads any components provided by the bundle whose state
+ * changed. If the bundle has been started, the components are loaded. If
+ * the bundle is about to stop, the components are unloaded.
+ *
+ * @param event The <code>BundleEvent</code> representing the bundle state
+ * change.
+ */
+ public void bundleChanged(BundleEvent event) {
+ // Take care: This is synchronous - take care to not block the system !!
+ Loader theLoader = this.loader;
+ if (theLoader != null) {
+ switch (event.getType()) {
+ case BundleEvent.INSTALLED:
+ // register types when the bundle gets installed
+ theLoader.registerBundle(event.getBundle());
+ break;
+
+ case BundleEvent.UNINSTALLED:
+ theLoader.unregisterBundle(event.getBundle());
+ break;
+
+ case BundleEvent.UPDATED:
+ theLoader.updateBundle(event.getBundle());
+ }
}
}
@@ -313,6 +530,7 @@
/**
* This method must be called if overwritten by implementations !!
+ *
* @throws nothing, but allow derived classes to throw any Exception
*/
protected void activate(ComponentContext componentContext) throws Exception {
@@ -320,8 +538,14 @@
@SuppressWarnings("unchecked")
Dictionary<String, Object> properties = componentContext.getProperties();
- this.defaultWorkspace = this.getProperty(properties, PROPERTY_DEFAULT_WORKSPACE,
- DEFAULT_WORKSPACE);
+
+ // ensure the default workspace is not null and not empty
+ this.defaultWorkspace = this.getProperty(properties,
+ PROPERTY_DEFAULT_WORKSPACE, DEFAULT_WORKSPACE);
+ if (this.defaultWorkspace != null
+ && this.defaultWorkspace.length() == 0) {
+ this.defaultWorkspace = null;
+ }
this.anonUser = this.getProperty(properties, PROPERTY_ANONYMOUS_USER,
DEFAULT_ANONYMOUS_USER);
@@ -333,77 +557,48 @@
this.adminPass = this.getProperty(properties, PROPERTY_ADMIN_PASS,
DEFAULT_ADMIN_PASS).toCharArray();
- this.loader = new Loader(this);
-
+ setPollTimeActive(getIntProperty(properties, PROPERTY_POLL_ACTIVE));
+ setPollTimeInActive(getIntProperty(properties, PROPERTY_POLL_INACTIVE));
+
componentContext.getBundleContext().addBundleListener(this);
- // TODO: Consider running this in the background !!
- // FIXME: Commented while SLING-132 is still unfixed
- Bundle[] bundles = componentContext.getBundleContext().getBundles();
- for (int i = 0; i < bundles.length; i++) {
- if ((bundles[i].getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) {
- // load content for bundles which are neither INSTALLED nor
- // UNINSTALLED
- this.loader.registerBundle(bundles[i]);
- }
- }
+ startRepositoryPinger();
}
/**
* This method must be called if overwritten by implementations !!
- *
+ *
* @param componentContext
*/
protected void deactivate(ComponentContext componentContext) {
componentContext.getBundleContext().removeBundleListener(this);
- if (this.poolManager != null) {
- this.poolManager.dispose();
- this.poolManager = null;
- }
- if ( this.loader != null ) {
- this.loader.dispose();
- this.loader = null;
- }
+ stopRepositoryPinger();
this.componentContext = null;
}
-
- /**
- * Loads and unloads any components provided by the bundle whose state
- * changed. If the bundle has been started, the components are loaded. If
- * the bundle is about to stop, the components are unloaded.
- *
- * @param event The <code>BundleEvent</code> representing the bundle state
- * change.
- */
- public void bundleChanged(BundleEvent event) {
- // TODO: This is synchronous - take care to not block the system !!
- switch (event.getType()) {
- case BundleEvent.INSTALLED:
- // register content and types when the bundle content is
- // available
- this.loader.registerBundle(event.getBundle());
- break;
-
- case BundleEvent.UNINSTALLED:
- this.loader.unregisterBundle(event.getBundle());
- break;
- case BundleEvent.UPDATED:
- this.loader.updateBundle(event.getBundle());
+
+ protected void bindLog(LogService log) {
+ this.log = log;
+ }
+
+ protected void unbindLog(LogService log) {
+ if (this.log == log) {
+ log = null;
}
}
// ---------- internal -----------------------------------------------------
- private String getProperty(Dictionary<String, Object> properties, String name,
- String defaultValue) {
+ private String getProperty(Dictionary<String, Object> properties,
+ String name, String defaultValue) {
Object prop = properties.get(name);
return (prop instanceof String) ? (String) prop : defaultValue;
}
- private int getIntProperty(Dictionary<String, Object> properties, String name) {
+ private int getIntProperty(Dictionary<String, Object> properties,
+ String name) {
Object prop = properties.get(name);
if (prop instanceof Number) {
return ((Number) prop).intValue();
@@ -419,13 +614,14 @@
}
private boolean createWorkspace(String workspace) {
- this.log(LogService.LOG_INFO, "login: Requested workspace " + workspace
- + " does not exist, trying to create");
+ this.log(LogService.LOG_INFO, "createWorkspace: Requested workspace "
+ + workspace + " does not exist, trying to create");
Session tmpSession = null;
try {
- SimpleCredentials sc = new SimpleCredentials(this.adminUser, this.adminPass);
- tmpSession = this.getDelegatee().login(sc);
+ SimpleCredentials sc = new SimpleCredentials(this.adminUser,
+ this.adminPass);
+ tmpSession = this.getRepository().login(sc);
Workspace defaultWs = tmpSession.getWorkspace();
if (defaultWs instanceof JackrabbitWorkspace) {
((JackrabbitWorkspace) defaultWs).createWorkspace(workspace);
@@ -433,11 +629,13 @@
}
// not Jackrabbit
- this.log(LogService.LOG_ERROR, "login: Cannot create requested workspace "
- + workspace + ": Jackrabbit is required");
+ this.log(LogService.LOG_ERROR,
+ "createWorkspace: Cannot create requested workspace "
+ + workspace + ": Jackrabbit is required");
} catch (Throwable t) {
- this.log(LogService.LOG_ERROR, "login: Cannot create requested workspace "
- + workspace, t);
+ this.log(LogService.LOG_ERROR,
+ "createWorkspace: Cannot create requested workspace "
+ + workspace, t);
} finally {
if (tmpSession != null) {
tmpSession.logout();
@@ -447,4 +645,186 @@
// fall back to failure
return false;
}
+
+ // ---------- Background operation checking repository availability --------
+
+ private void setPollTimeActive(int seconds) {
+ if (seconds < MIN_POLL) {
+ seconds = DEFAULT_POLL_ACTIVE;
+ }
+ pollTimeActive = 1000L * seconds;
+ }
+
+ private void setPollTimeInActive(int seconds) {
+ if (seconds < MIN_POLL) {
+ seconds = DEFAULT_POLL_INACTIVE;
+ }
+ pollTimeInActive = 1000L * seconds;
+ }
+
+ private void startRepositoryPinger() {
+ if (repositoryPinger != null) {
+ // make sure the ping will be running
+ running = true;
+
+ // create and start the thread
+ repositoryPinger = new Thread(this, "Repository Pinger");
+ repositoryPinger.start();
+ }
+ }
+
+ private void stopRepositoryPinger() {
+
+ // make sure the thread is terminating
+ running = false;
+
+ // nothing to do if the thread is not running at all
+ Thread rpThread = repositoryPinger;
+ if (rpThread == null) {
+ return;
+ }
+
+ // clear the repositoryPinger thread field
+ repositoryPinger = null;
+
+ // notify the thread for it to be able to shut down
+ synchronized (rpThread) {
+ rpThread.notifyAll();
+ }
+
+ // wait at most 10 seconds for the thread to terminate
+ try {
+ rpThread.join(10000L);
+ } catch (InterruptedException ie) {
+ // don't care here
+ }
+
+ // consider it an error if the thread is still running !!
+ if (rpThread.isAlive()) {
+ log(LogService.LOG_ERROR,
+ "stopRepositoryPinger: Timed waiting for thread "
+ + rpThread + " to terminate");
+ }
+
+ }
+
+ private boolean startRepository() {
+ try {
+ Repository newRepo = acquireRepository();
+ if (newRepo != null) {
+
+ // ensure we really have the repository
+ if (pingRepository(newRepo)) {
+ repository = newRepo;
+
+ setupRepository(newRepo);
+ repositoryService = registerService();
+
+ return true;
+ }
+
+ // otherwise let go off the repository and fail startup
+ log(LogService.LOG_INFO, "startRepository: Acquired Repository is not responsive, failing");
+ disposeRepository(repository);
+ }
+ } catch (Throwable t) {
+ // consider an uncaught problem an error
+ log(
+ LogService.LOG_ERROR,
+ "startRepository: Uncaught problem trying to provide repository access",
+ t);
+
+ // repository might be partially start, stop anything left
+ stopRepository();
+ }
+
+ return false;
+ }
+
+ private void stopRepository() {
+ if (repositoryService != null) {
+ try {
+ unregisterService(repositoryService);
+ } catch (Throwable t) {
+ log(
+ LogService.LOG_INFO,
+ "stopRepository: Uncaught problem unregistering the repository service",
+ t);
+ }
+ repositoryService = null;
+ }
+
+ if (repository != null) {
+ Repository oldRepo = repository;
+ repository = null;
+
+ try {
+ tearDown(oldRepo);
+ } catch (Throwable t) {
+ log(
+ LogService.LOG_INFO,
+ "stopRepository: Uncaught problem tearing down the repository",
+ t);
+ }
+
+ try {
+ disposeRepository(oldRepo);
+ } catch (Throwable t) {
+ log(
+ LogService.LOG_INFO,
+ "stopRepository: Uncaught problem disposing the repository",
+ t);
+ }
+ }
+ }
+
+ public void run() {
+ long pollTime = pollTimeInActive;
+ Object waitLock = repositoryPinger;
+
+ try {
+
+ while (running) {
+
+ Repository repo = repository;
+ if (repo == null && running) {
+
+ if (startRepository()) {
+ pollTime = pollTimeActive;
+ }
+
+ } else if (!pingRepository(repo)) {
+
+ log(LogService.LOG_INFO,
+ "run: Repository not accessible any more, unregistering service");
+ stopRepository();
+ pollTime = pollTimeInActive;
+
+ } else {
+
+ log(LogService.LOG_DEBUG,
+ "run: Repository available, checking again in "
+ + pollTime + "ms");
+ }
+
+
+ // only wait if still running
+ synchronized (waitLock) {
+ if (running) {
+ try {
+ waitLock.wait(pollTime);
+ } catch (InterruptedException ie) {
+ // don't care, go ahead
+ }
+ }
+ }
+ }
+
+ } finally {
+ // whatever goes on, make sure the repository is disposed off
+ // at the end of the thread....
+ stopRepository();
+ }
+ }
+
}
Modified: incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/SessionPool.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/SessionPool.java?rev=633823&r1=633822&r2=633823&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/SessionPool.java (original)
+++ incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/SessionPool.java Wed Mar 5 03:35:06 2008
@@ -117,7 +117,7 @@
* sessions from this pool to drop below the configured number of maximum
* active sessions.
*
- * @see #PARAM_MAX_ACTIVE_SESSIONS_WAIT
+ * @see #PROPERTY_MAX_ACTIVE_SESSIONS_WAIT
* @see #DEFAULT_MAX_ACTIVE_SESSIONS_WAIT
* @see #getMaxActiveSessionsWait()
* @see #setMaxActiveSessionsWait(long)
Modified: incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java?rev=633823&r1=633822&r2=633823&view=diff
==============================================================================
--- incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java (original)
+++ incubator/sling/trunk/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java Wed Mar 5 03:35:06 2008
@@ -61,9 +61,19 @@
/** Namespace prefix table. */
private final Map<Long, NamespaceEntry[]> namespaceTable = new HashMap<Long, NamespaceEntry[]>();
- public Loader(AbstractSlingRepository repository) {
+ public Loader(AbstractSlingRepository repository, Bundle[] existingBundles) {
this.slingRepository = repository;
this.delayedBundles = new LinkedList<Bundle>();
+
+ // scan existing bundles
+ for (Bundle bundle : existingBundles) {
+ if ((bundle.getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) {
+ // load content for bundles which are neither INSTALLED nor
+ // UNINSTALLED
+ registerBundle(bundle);
+ }
+ }
+
}
public void dispose() {