This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-base.git
commit 6f5771acf4b943840c477a8621e54c43a3497b97 Author: Robert Munteanu <[email protected]> AuthorDate: Wed Aug 8 12:40:03 2018 +0300 SLING-7811 - NPE when repository is starting up Make the repository initialisation and startup process more robust against restarts. It is possible that while a the repository startup is happening in an async manner in the "Apache Sling Repository Startup Thread" a stop is requested. This thread should be notified of any stop requests and gracefully handle the shutdown. --- .../jcr/base/AbstractSlingRepositoryManager.java | 31 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java index bdbdcbc..bedb9e7 100644 --- a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java +++ b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.Dictionary; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import javax.jcr.Repository; @@ -109,6 +110,10 @@ public abstract class AbstractSlingRepositoryManager { private final Object repoInitLock = new Object(); + private volatile Thread startupThread; + + private volatile boolean stopRequested; + /** * Returns the default workspace, which may be <code>null</code> meaning to * use the repository provided default workspace. @@ -447,17 +452,20 @@ public abstract class AbstractSlingRepositoryManager { // start repository asynchronously to allow LoginAdminWhitelist to become available // NOTE: making this conditional allows tests to register a mock whitelist before // activating the RepositoryManager, so they don't need to deal with async startup - new Thread("Apache Sling Repository Startup Thread") { + startupThread = new Thread("Apache Sling Repository Startup Thread") { @Override public void run() { try { waitForWhitelist.await(); initializeAndRegisterRepositoryService(); } catch (InterruptedException e) { - throw new RuntimeException("Interrupted while waiting for LoginAdminWhitelist", e); + log.info("Interrupted while waiting for the {} service, cancelling repository initialisation", LoginAdminWhitelist.class.getSimpleName(), e); + Thread.currentThread().interrupt(); + return; } } - }.start(); + }; + startupThread.start(); } private boolean isRepositoryServiceRegistered() { @@ -474,6 +482,11 @@ public abstract class AbstractSlingRepositoryManager { // ensure we really have the repository log.debug("start: got a Repository"); this.repository = newRepo; + if ( stopRequested ) { + log.debug("Stop requested, cancelling initialisation and stopping repository"); + stop(); + return; + } synchronized ( this.repoInitLock ) { this.masterSlingRepository = this.create(this.bundleContext.getBundle()); @@ -547,6 +560,18 @@ public abstract class AbstractSlingRepositoryManager { */ protected final void stop() { + stopRequested = true; + if ( startupThread != null && startupThread != Thread.currentThread() ) { + try { + startupThread.interrupt(); + startupThread.join(); + } catch (InterruptedException e) { + log.debug("Interrupted while waiting for the " + startupThread.getName() + " to complete.", e); + Thread.currentThread().interrupt(); + } + startupThread = null; + } + // ensure the repository is really disposed off if (repository != null || isRepositoryServiceRegistered()) { log.info("stop: Repository still running, forcing shutdown");
