From 9bf9c0c17d8131c46dea9ee3ebad394720f3f344 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 11 Jan 2022 10:56:38 +0100 Subject: [PATCH] Improve JCR repository lifecycle --- .../internal/RepositoryContextsFactory.java | 93 ++++++++++--------- .../argeo/cms/internal/osgi/CmsActivator.java | 2 + .../{runtime => osgi}/GogoShellKiller.java | 9 +- .../cms/internal/runtime/CmsStateImpl.java | 45 +++++---- 4 files changed, 78 insertions(+), 71 deletions(-) rename org.argeo.cms/src/org/argeo/cms/internal/{runtime => osgi}/GogoShellKiller.java (88%) diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/RepositoryContextsFactory.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/RepositoryContextsFactory.java index 1a1fda1f0..2b9ad0043 100644 --- a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/RepositoryContextsFactory.java +++ b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/RepositoryContextsFactory.java @@ -1,11 +1,14 @@ package org.argeo.cms.jcr.internal; +import java.io.IOException; import java.net.URI; +import java.net.URISyntaxException; import java.util.Dictionary; import java.util.HashMap; import java.util.Map; import javax.jcr.Repository; +import javax.jcr.RepositoryException; import javax.jcr.RepositoryFactory; import org.apache.jackrabbit.core.RepositoryContext; @@ -26,15 +29,16 @@ public class RepositoryContextsFactory implements ManagedServiceFactory { private Map repositories = new HashMap(); private Map pidToCn = new HashMap(); - + public void init() { - + } public void destroy() { for (String pid : repositories.keySet()) { try { - repositories.get(pid).getRepository().shutdown(); + RepositoryContext repositoryContext = repositories.get(pid); + repositoryContext.getRepository().shutdown(); if (log.isDebugEnabled()) log.debug("Shut down repository " + pid + (pidToCn.containsKey(pid) ? " (" + pidToCn.get(pid) + ")" : "")); @@ -44,7 +48,6 @@ public class RepositoryContextsFactory implements ManagedServiceFactory { } } - @Override public String getName() { return "Jackrabbit repository service factory"; @@ -58,10 +61,19 @@ public class RepositoryContextsFactory implements ManagedServiceFactory { if (properties == null) return; - if (repositories.containsKey(pid)) { - log.warn("Ignore update of Jackrabbit repository " + pid); - return; - } + Object cn = properties.get(CmsConstants.CN); + if (cn != null) + for (String otherPid : pidToCn.keySet()) { + Object o = pidToCn.get(otherPid); + if (cn.equals(o)) { + RepositoryContext repositoryContext = repositories.remove(otherPid); + repositories.put(pid, repositoryContext); + if (log.isDebugEnabled()) + log.debug("Ignore update of Jackrabbit repository " + cn); + // FIXME perform a proper update (also of the OSGi service) + return; + } + } try { Object labeledUri = properties.get(RepoConf.labeledUri.name()); @@ -72,7 +84,6 @@ public class RepositoryContextsFactory implements ManagedServiceFactory { Dictionary props = LangUtils.dict(Constants.SERVICE_PID, pid); // props.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, // properties.get(RepoConf.labeledUri.name())); - Object cn = properties.get(CmsConstants.CN); if (cn != null) { props.put(CmsConstants.CN, cn); // props.put(NodeConstants.JCR_REPOSITORY_ALIAS, cn); @@ -80,45 +91,38 @@ public class RepositoryContextsFactory implements ManagedServiceFactory { } CmsJcrActivator.registerService(RepositoryContext.class, repositoryContext, props); } else { - try { - Object cn = properties.get(CmsConstants.CN); - Object defaultWorkspace = properties.get(RepoConf.defaultWorkspace.name()); - if (defaultWorkspace == null) - defaultWorkspace = RepoConf.defaultWorkspace.getDefault(); - URI uri = new URI(labeledUri.toString()); + Object defaultWorkspace = properties.get(RepoConf.defaultWorkspace.name()); + if (defaultWorkspace == null) + defaultWorkspace = RepoConf.defaultWorkspace.getDefault(); + URI uri = new URI(labeledUri.toString()); // RepositoryFactory repositoryFactory = bc // .getService(bc.getServiceReference(RepositoryFactory.class)); - RepositoryFactory repositoryFactory = CmsJcrActivator.getService(RepositoryFactory.class); - Map parameters = new HashMap(); - parameters.put(RepoConf.labeledUri.name(), uri.toString()); - parameters.put(RepoConf.defaultWorkspace.name(), defaultWorkspace.toString()); - Repository repository = repositoryFactory.getRepository(parameters); - // Repository repository = NodeUtils.getRepositoryByUri(repositoryFactory, - // uri.toString()); - Dictionary props = LangUtils.dict(Constants.SERVICE_PID, pid); - props.put(RepoConf.labeledUri.name(), - new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), null, null) - .toString()); - if (cn != null) { - props.put(CmsConstants.CN, cn); - // props.put(NodeConstants.JCR_REPOSITORY_ALIAS, cn); - pidToCn.put(pid, cn); - } - CmsJcrActivator.registerService(Repository.class, repository, props); - - // home - if (cn.equals(CmsConstants.NODE_REPOSITORY)) { - Dictionary homeProps = LangUtils.dict(CmsConstants.CN, - CmsConstants.EGO_REPOSITORY); - EgoRepository homeRepository = new EgoRepository(repository, true); - CmsJcrActivator.registerService(Repository.class, homeRepository, homeProps); - } - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + RepositoryFactory repositoryFactory = CmsJcrActivator.getService(RepositoryFactory.class); + Map parameters = new HashMap(); + parameters.put(RepoConf.labeledUri.name(), uri.toString()); + parameters.put(RepoConf.defaultWorkspace.name(), defaultWorkspace.toString()); + Repository repository = repositoryFactory.getRepository(parameters); + // Repository repository = NodeUtils.getRepositoryByUri(repositoryFactory, + // uri.toString()); + Dictionary props = LangUtils.dict(Constants.SERVICE_PID, pid); + props.put(RepoConf.labeledUri.name(), + new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), null, null) + .toString()); + if (cn != null) { + props.put(CmsConstants.CN, cn); + // props.put(NodeConstants.JCR_REPOSITORY_ALIAS, cn); + pidToCn.put(pid, cn); + } + CmsJcrActivator.registerService(Repository.class, repository, props); + + // home + if (cn.equals(CmsConstants.NODE_REPOSITORY)) { + Dictionary homeProps = LangUtils.dict(CmsConstants.CN, CmsConstants.EGO_REPOSITORY); + EgoRepository homeRepository = new EgoRepository(repository, true); + CmsJcrActivator.registerService(Repository.class, homeRepository, homeProps); } } - } catch (Exception e) { + } catch (RepositoryException | URISyntaxException | IOException e) { throw new IllegalStateException("Cannot create Jackrabbit repository " + pid, e); } @@ -132,5 +136,4 @@ public class RepositoryContextsFactory implements ManagedServiceFactory { log.debug("Deleted repository " + pid); } - } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsActivator.java b/org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsActivator.java index d28ffdbb2..264f0c1b9 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsActivator.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsActivator.java @@ -89,6 +89,8 @@ public class CmsActivator implements BundleActivator { } catch (Exception e) { log.error("CMS activator shutdown failed", e); } + + new GogoShellKiller().start(); } private void initSecurity() { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/GogoShellKiller.java b/org.argeo.cms/src/org/argeo/cms/internal/osgi/GogoShellKiller.java similarity index 88% rename from org.argeo.cms/src/org/argeo/cms/internal/runtime/GogoShellKiller.java rename to org.argeo.cms/src/org/argeo/cms/internal/osgi/GogoShellKiller.java index 56df43a8a..85c686a0a 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/GogoShellKiller.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/osgi/GogoShellKiller.java @@ -1,4 +1,6 @@ -package org.argeo.cms.internal.runtime; +package org.argeo.cms.internal.osgi; + +import java.io.IOException; /** * Workaround for killing Gogo shell by system shutdown. @@ -16,7 +18,7 @@ class GogoShellKiller extends Thread { public void run() { ThreadGroup rootTg = getRootThreadGroup(null); Thread gogoShellThread = findGogoShellThread(rootTg); - if (gogoShellThread == null) + if (gogoShellThread == null) // no need to bother if it is not here return; while (getNonDaemonCount(rootTg) > 2) { try { @@ -28,8 +30,9 @@ class GogoShellKiller extends Thread { gogoShellThread = findGogoShellThread(rootTg); if (gogoShellThread == null) return; + System.exit(0); // No non-deamon threads left, forcibly halting the VM - Runtime.getRuntime().halt(0); + //Runtime.getRuntime().halt(0); } private ThreadGroup getRootThreadGroup(ThreadGroup tg) { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java index cf203e5e6..c07128394 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java @@ -3,8 +3,6 @@ package org.argeo.cms.internal.runtime; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; import javax.security.auth.login.Configuration; @@ -29,7 +27,7 @@ public class CmsStateImpl implements CmsState { private Long availableSince; // private ThreadGroup threadGroup = new ThreadGroup("CMS"); - private List stopHooks = new ArrayList<>(); +// private List stopHooks = new ArrayList<>(); private String stateUuid; // private final boolean cleanState; @@ -180,15 +178,16 @@ public class CmsStateImpl implements CmsState { public void destroy() { if (log.isDebugEnabled()) log.debug("CMS stopping... (" + this.stateUuid + ")"); +// new GogoShellKiller().start(); // In a different thread in order to avoid interruptions - Thread stopHookThread = new Thread(() -> applyStopHooks(), "Apply Argeo Stop Hooks"); - stopHookThread.start(); - try { - stopHookThread.join(10 * 60 * 1000); - } catch (InterruptedException e) { - // silent - } +// Thread stopHookThread = new Thread(() -> applyStopHooks(), "Apply Argeo Stop Hooks"); +// stopHookThread.start(); +// try { +// stopHookThread.join(10 * 60 * 1000); +// } catch (InterruptedException e) { +// // silent +// } // internalExecutorService.shutdown(); @@ -197,19 +196,19 @@ public class CmsStateImpl implements CmsState { } /** Apply shutdown hoos in reverse order. */ - private void applyStopHooks() { - for (int i = stopHooks.size() - 1; i >= 0; i--) { - try { - stopHooks.get(i).run(); - } catch (Exception e) { - log.error("Could not run shutdown hook #" + i); - } - } - // Clean hanging Gogo shell thread - new GogoShellKiller().start(); - -// instance = null; - } +// private void applyStopHooks() { +//// for (int i = stopHooks.size() - 1; i >= 0; i--) { +//// try { +//// stopHooks.get(i).run(); +//// } catch (Exception e) { +//// log.error("Could not run shutdown hook #" + i); +//// } +//// } +// // Clean hanging Gogo shell thread +// new GogoShellKiller().start(); +// +//// instance = null; +// } // @Override // public boolean isClean() { -- 2.30.2