From: mbaudier Date: Thu, 2 Nov 2017 14:48:31 +0000 (+0100) Subject: Improve node deployment X-Git-Tag: argeo-commons-2.1.70~45 X-Git-Url: http://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=5b5c2b97eee9edd037e198acadf8b416a973863f Improve node deployment --- diff --git a/dist/argeo-node/pom.xml b/dist/argeo-node/pom.xml index e53a115ce..da4e22949 100644 --- a/dist/argeo-node/pom.xml +++ b/dist/argeo-node/pom.xml @@ -65,7 +65,7 @@ rpm/usr/sbin - node-service + nodectl diff --git a/dist/argeo-node/rpm/etc/node/config.ini b/dist/argeo-node/rpm/etc/node/config.ini index 44a2170e5..ec75a4f7a 100644 --- a/dist/argeo-node/rpm/etc/node/config.ini +++ b/dist/argeo-node/rpm/etc/node/config.ini @@ -1,11 +1,20 @@ -#argeo.osgi.baseUrl=http://forge.argeo.org/data/java/argeo-2.1/ -#argeo.osgi.distributionUrl=org/argeo/commons/org.argeo.dep.cms.sdk/2.1.65/org.argeo.dep.cms.sdk-2.1.69.jar +argeo.node.repo.type=h2 +org.osgi.service.http.port=8080 +osgi.console=2323 + +# Backend +#argeo.osgi.start.5.apps=org.argeo.suite.apps + +# UI +#argeo.osgi.start.6.apps=org.argeo.suite.apps.web,org.argeo.suite.workbench.rap + +# DO NOT CHANGE BELOW UNLESS YOU KNOW WHAT YOU ARE DOING +osgi.clean=true +osgi.bundles=org.argeo.osgi.boot.jar@start argeo.osgi.bundles=\ /usr/local/share/osgi;in=**/*.jar,\ /usr/share/osgi;in=**/*.jar -argeo.osgi.boot.debug=true - argeo.osgi.start.2.node=\ org.eclipse.equinox.http.servlet,\ org.eclipse.equinox.http.jetty,\ @@ -16,17 +25,10 @@ org.eclipse.rap.rwt.osgi argeo.osgi.start.3.node=\ org.argeo.cms -argeo.osgi.start.4.apps=\ -org.eclipse.gemini.blueprint.extender - -argeo.osgi.start.4.workbench=\ -org.eclipse.equinox.http.registry,\ +argeo.osgi.start.4.node=\ +org.eclipse.gemini.blueprint.extender,\ +org.eclipse.equinox.http.registry -argeo.node.repo.type=h2 -org.osgi.service.http.port=8080 - -# DO NOT CHANGE BELOW UNLESS YOU KNOW WHAT YOU ARE DOING -osgi.bundles=org.argeo.osgi.boot.jar@start org.osgi.framework.bootdelegation=com.sun.jndi.ldap,\ com.sun.jndi.ldap.sasl,\ com.sun.security.jgss,\ diff --git a/dist/argeo-node/rpm/etc/node/log4j.properties b/dist/argeo-node/rpm/etc/node/log4j.properties index f79dc2c6b..d53b851de 100644 --- a/dist/argeo-node/rpm/etc/node/log4j.properties +++ b/dist/argeo-node/rpm/etc/node/log4j.properties @@ -1,13 +1,15 @@ -log4j.rootLogger=WARN, console +log4j.rootLogger=WARN, console, file -log4j.logger.org.argeo=DEBUG +log4j.logger.org.argeo=INFO ## Appenders log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c - [%t]%n +log4j.appender.console.layout.ConversionPattern=%-5p %m%n -log4j.appender.file=org.apache.log4j.RollingFileAppender -log4j.appender.file.File=/var/log/node/node.log +log4j.appender.file=org.apache.log4j.DailyRollingFileAppender +log4j.appender.file.File=/var/log/node/node.csv log4j.appender.file.layout=org.apache.log4j.PatternLayout -log4j.appender.file.layout.ConversionPattern= %-5p %d{ISO8601} [%15.15t] %m - %c%n +log4j.appender.file.layout.ConversionPattern=%d{ISO8601};"%m";%c;%p%n +log4j.appender.file.bufferedIO=true +log4j.appender.file.immediateFlush=false diff --git a/dist/argeo-node/rpm/usr/lib/systemd/system/node.service b/dist/argeo-node/rpm/usr/lib/systemd/system/node.service index 45fab9ada..80cd827a1 100644 --- a/dist/argeo-node/rpm/usr/lib/systemd/system/node.service +++ b/dist/argeo-node/rpm/usr/lib/systemd/system/node.service @@ -6,9 +6,8 @@ Wants=postgresql.service [Service] Type=simple PIDFile=/var/run/node/node.pid -ExecStart=/usr/sbin/node-service start -#ExecReload=/usr/sbin/node-service reload -#ExecStop=/usr/sbin/node-service stop +ExecStart=/usr/sbin/nodectl start +ExecReload=/usr/sbin/nodectl reload SuccessExitStatus=143 [Install] diff --git a/dist/argeo-node/rpm/usr/sbin/node-service b/dist/argeo-node/rpm/usr/sbin/node-service deleted file mode 100755 index 7accca912..000000000 --- a/dist/argeo-node/rpm/usr/sbin/node-service +++ /dev/null @@ -1,146 +0,0 @@ -#!/bin/sh -APP=node - -JVM=java - -# Directories and files -CONF_DIR=/etc/$APP - -EXEC_DIR=/var/lib/$APP -DATA_DIR=$EXEC_DIR/data -CONF_RW=$EXEC_DIR/state -LOG_DIR=/var/log/$APP -LOG_FILE=$LOG_DIR/$APP.log - -RUN_DIR=/var/run/$APP -PID_FILE=$RUN_DIR/$APP.pid -SHUTDOWN_FILE=$RUN_DIR/$APP.shutdown - -OSGI_INSTALL_AREA=/usr/share/osgi/boot -OSGI_FRAMEWORK=$OSGI_INSTALL_AREA/org.eclipse.osgi.jar - -# Overwrite variables -if [ -f $CONF_DIR/settings.sh ];then - . $CONF_DIR/settings.sh -fi - -RETVAL=0 - -start() { - if [ -f $PID_FILE ];then - PID=`cat $PID_FILE` - kill -0 $PID &> /dev/null - PID_EXISTS=$? - if [ $PID_EXISTS -eq 0 ]; then - echo $APP already running with pid $PID - RETVAL=1 - return $RETVAL - else - echo Old $APP process with pid $PID is dead, removing $PID_FILE - rm -f $PID_FILE - fi - fi - - if [ ! -f $CONF_RW/config.ini ]; then - cp --preserve $CONF_DIR/config.ini $CONF_RW/config.ini - fi - touch $SHUTDOWN_FILE - cd $EXEC_DIR - $JVM \ - -Dargeo.osgi.shutdownFile="$SHUTDOWN_FILE" \ - -Dlog4j.configuration="file:$CONF_DIR/log4j.properties" \ - -Djava.security.manager= \ - -Djava.security.policy="file:$CONF_DIR/node.policy" \ - $JAVA_OPTS -jar $OSGI_FRAMEWORK \ - -configuration "$CONF_RW" \ - -data "$DATA_DIR" -} - -stop() { - if [ -f $PID_FILE ];then - PID=`cat $PID_FILE` - kill -0 $PID &> /dev/null - PID_EXISTS=$? - if [ $PID_EXISTS -ne 0 ]; then - echo Dead $APP process with pid $PID, removing $PID_FILE - rm -f $PID_FILE - RETVAL=1 - return $RETVAL - fi - else - echo $APP is not running - RETVAL=1 - return $RETVAL - fi - - # notifies application by removing the shutdown file - rm -f $SHUTDOWN_FILE - - # wait 5 min for application to shutdown, then kill it - TIMEOUT=$((5*60)) - BEGIN=$(date +%s) - while kill -0 $PID &> /dev/null - do - sleep 1 - NOW=$(date +%s) - DURATION=$(($NOW-$BEGIN)) - if [ $DURATION -gt $TIMEOUT ]; then - kill -9 $PID - echo Forcibly killed $APP with pid $PID - RETVAL=1 - fi - done - - # remove pid file - rm -f $PID_FILE - return $RETVAL - -# timeout is only available in EL6 -# timeout 5m sh << EOF -#while kill -0 $PID &> /dev/null; do sleep 1; done -#EOF -# TIMEOUT_EXIT=$? -# if [ $TIMEOUT_EXIT -eq 124 ];then -# kill -9 $PID -# RETVAL=1 -# echo Killed $APP with pid $PID -# else -# echo Stopped $APP with pid $PID -# fi -# rm -f $PID_FILE -# return $RETVAL -} - -status() { - if [ -f $PID_FILE ];then - PID=`cat $PID_FILE` - else - echo $APP is not running - return $RETVAL - fi - kill -0 $PID &> /dev/null - PID_EXISTS=$? - if [ $PID_EXISTS -eq 0 ]; then - echo $APP is running with pid $PID ... - else - echo No $APP process with pid $PID, removing $PID_FILE - rm -f $PID_FILE - fi - return $RETVAL -} - -# main -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - status - ;; - *) - echo $"Usage: $0 {start|stop|status}" - exit 1 -esac \ No newline at end of file diff --git a/dist/argeo-node/rpm/usr/sbin/nodectl b/dist/argeo-node/rpm/usr/sbin/nodectl new file mode 100755 index 000000000..26fe3eeaf --- /dev/null +++ b/dist/argeo-node/rpm/usr/sbin/nodectl @@ -0,0 +1,152 @@ +#!/bin/sh +APP=node + +JVM=java + +# Directories and files +CONF_DIR=/etc/$APP + +EXEC_DIR=/var/lib/$APP +DATA_DIR=$EXEC_DIR/data +CONF_RW=$EXEC_DIR/state +LOG_DIR=/var/log/$APP +LOG_FILE=$LOG_DIR/$APP.log + +RUN_DIR=/var/run/$APP +PID_FILE=$RUN_DIR/$APP.pid +#SHUTDOWN_FILE=$RUN_DIR/$APP.shutdown + +OSGI_INSTALL_AREA=/usr/share/osgi/boot +OSGI_FRAMEWORK=$OSGI_INSTALL_AREA/org.eclipse.osgi.jar + +# Overwrite variables +if [ -f $CONF_DIR/settings.sh ];then + . $CONF_DIR/settings.sh +fi + +RETVAL=0 + +start() { + if [ -f $PID_FILE ];then + PID=`cat $PID_FILE` + kill -0 $PID &> /dev/null + PID_EXISTS=$? + if [ $PID_EXISTS -eq 0 ]; then + echo $APP already running with pid $PID + RETVAL=1 + return $RETVAL + else + echo Old $APP process with pid $PID is dead, removing $PID_FILE + rm -f $PID_FILE + fi + fi + +# if [ ! -f $CONF_RW/config.ini ]; then + cp --preserve $CONF_DIR/config.ini $CONF_RW/config.ini +# fi +# touch $SHUTDOWN_FILE + cd $EXEC_DIR + $JVM \ + -Dlog4j.configuration="file:$CONF_DIR/log4j.properties" \ + -Djava.security.manager= \ + -Djava.security.policy="file:$CONF_DIR/node.policy" \ + $JAVA_OPTS -jar $OSGI_FRAMEWORK \ + -configuration "$CONF_RW" \ + -data "$DATA_DIR" +} + +reload() { + echo Not yet implemented +} + +stop() { + if [ -f $PID_FILE ];then + PID=`cat $PID_FILE` + kill -0 $PID &> /dev/null + PID_EXISTS=$? + if [ $PID_EXISTS -ne 0 ]; then + echo Dead $APP process with pid $PID, removing $PID_FILE + rm -f $PID_FILE + RETVAL=1 + return $RETVAL + fi + else + echo $APP is not running + RETVAL=1 + return $RETVAL + fi + + # notifies application by removing the shutdown file + rm -f $SHUTDOWN_FILE + + # wait 10 min for application to shutdown, then kill it + TIMEOUT=$((10*60)) + BEGIN=$(date +%s) + while kill -0 $PID &> /dev/null + do + sleep 1 + NOW=$(date +%s) + DURATION=$(($NOW-$BEGIN)) + if [ $DURATION -gt $TIMEOUT ]; then + kill -9 $PID + echo Forcibly killed $APP with pid $PID + RETVAL=1 + fi + done + + # remove pid file + rm -f $PID_FILE + return $RETVAL + +# timeout is only available in EL6 +# timeout 5m sh << EOF +#while kill -0 $PID &> /dev/null; do sleep 1; done +#EOF +# TIMEOUT_EXIT=$? +# if [ $TIMEOUT_EXIT -eq 124 ];then +# kill -9 $PID +# RETVAL=1 +# echo Killed $APP with pid $PID +# else +# echo Stopped $APP with pid $PID +# fi +# rm -f $PID_FILE +# return $RETVAL +} + +status() { + if [ -f $PID_FILE ];then + PID=`cat $PID_FILE` + else + echo $APP is not running + return $RETVAL + fi + kill -0 $PID &> /dev/null + PID_EXISTS=$? + if [ $PID_EXISTS -eq 0 ]; then + echo $APP is running with pid $PID ... + else + echo No $APP process with pid $PID, removing $PID_FILE + rm -f $PID_FILE + fi + return $RETVAL +} + +# main +case "$1" in + start) + start + ;; + reload) + reload + ;; + stop) + stop + ;; + status) + status + ;; + *) + echo $"Usage: $0 {start|stop|status}" + exit 1 +esac \ No newline at end of file diff --git a/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleUxContext.java b/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleUxContext.java index a38444658..bde67e404 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleUxContext.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/util/SimpleUxContext.java @@ -43,7 +43,8 @@ public class SimpleUxContext implements UxContext { @Override public boolean isMasterData() { - return false; + // TODO make it configurable + return true; } } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java index a70235976..1efc9dc66 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java @@ -49,6 +49,7 @@ public class Activator implements BundleActivator { @Override public void start(BundleContext bundleContext) throws Exception { + Runtime.getRuntime().addShutdownHook(new CmsShutdown()); instance = this; this.bc = bundleContext; this.logReaderService = getService(LogReaderService.class); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java index 126c591e6..07c10f486 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java @@ -157,25 +157,25 @@ public class CmsDeployment implements NodeDeployment { long initDuration = System.currentTimeMillis() - begin; if (log.isTraceEnabled()) log.trace("Kernel initialization took " + initDuration + "ms"); - directorsCut(initDuration); + tributeToFreeSoftware(initDuration); } } - final private void directorsCut(long initDuration) { - // final long ms = 128l + (long) (Math.random() * 128d); - long ms = initDuration / 100; - log.info("Spend " + ms + "ms" + " reflecting on the progress brought to mankind" + " by Free Software..."); - long beginNano = System.nanoTime(); - try { - Thread.sleep(ms, 0); - } catch (InterruptedException e) { - // silent + final private void tributeToFreeSoftware(long initDuration) { + if (log.isTraceEnabled()) { + long ms = initDuration / 100; + log.trace("Spend " + ms + "ms" + " reflecting on the progress brought to mankind" + " by Free Software..."); + long beginNano = System.nanoTime(); + try { + Thread.sleep(ms, 0); + } catch (InterruptedException e) { + // silent + } + long durationNano = System.nanoTime() - beginNano; + final double M = 1000d * 1000d; + double sleepAccuracy = ((double) durationNano) / (ms * M); + log.trace("Sleep accuracy: " + String.format("%.2f", 100 - (sleepAccuracy * 100 - 100)) + " %"); } - long durationNano = System.nanoTime() - beginNano; - final double M = 1000d * 1000d; - double sleepAccuracy = ((double) durationNano) / (ms * M); - if (log.isDebugEnabled()) - log.debug("Sleep accuracy: " + String.format("%.2f", 100 - (sleepAccuracy * 100 - 100)) + " %"); } private void prepareNodeRepository(Repository deployedNodeRepository) { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsShutdown.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsShutdown.java new file mode 100644 index 000000000..a62ee7f10 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsShutdown.java @@ -0,0 +1,70 @@ +package org.argeo.cms.internal.kernel; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.launch.Framework; + +/** Shutdowns the OSGi framework */ +class CmsShutdown extends Thread { + public final int EXIT_OK = 0; + public final int EXIT_ERROR = 1; + public final int EXIT_TIMEOUT = 2; + public final int EXIT_UNKNOWN = 3; + + private final Log log = LogFactory.getLog(CmsShutdown.class); + // private final BundleContext bc = + // FrameworkUtil.getBundle(CmsShutdown.class).getBundleContext(); + private final Framework framework; + + /** Shutdown timeout in ms */ + private long timeout = 10 * 60 * 1000; + + public CmsShutdown() { + super("CMS Shutdown Hook"); + framework = (Framework) FrameworkUtil.getBundle(CmsShutdown.class).getBundleContext().getBundle(0); + } + + @Override + public void run() { + if (framework.getState() != Bundle.ACTIVE) { + return; + } + + if (log.isDebugEnabled()) + log.debug("Shutting down OSGi framework..."); + try { + // shutdown framework + framework.stop(); + // wait for shutdown + FrameworkEvent shutdownEvent = framework.waitForStop(timeout); + int stoppedType = shutdownEvent.getType(); + Runtime runtime = Runtime.getRuntime(); + if (stoppedType == FrameworkEvent.STOPPED) { + // close VM + //System.exit(EXIT_OK); + } else if (stoppedType == FrameworkEvent.ERROR) { + log.error("The OSGi framework stopped with an error"); + runtime.halt(EXIT_ERROR); + } else if (stoppedType == FrameworkEvent.WAIT_TIMEDOUT) { + log.error("The OSGi framework hasn't stopped after " + timeout + "ms." + + " Forcibly terminating the JVM..."); + runtime.halt(EXIT_TIMEOUT); + } else { + log.error("Unknown state of OSGi framework after " + timeout + "ms." + + " Forcibly terminating the JVM... (" + shutdownEvent + ")"); + runtime.halt(EXIT_UNKNOWN); + } + } catch (Exception e) { + e.printStackTrace(); + log.error("Unexpected exception " + e + " in shutdown hook. " + " Forcibly terminating the JVM..."); + Runtime.getRuntime().halt(EXIT_UNKNOWN); + } + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java index eebf71ccb..0b5bd0d48 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java @@ -5,6 +5,7 @@ import static bitronix.tm.TransactionManagerServices.getTransactionSynchronizati import static java.util.Locale.ENGLISH; import java.io.File; +import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.file.spi.FileSystemProvider; @@ -48,7 +49,7 @@ public class CmsState implements NodeState { private ThreadGroup threadGroup = new ThreadGroup("CMS"); private KernelThread kernelThread; - private List shutdownHooks = new ArrayList<>(); + private List stopHooks = new ArrayList<>(); private final String stateUuid; private final boolean cleanState; @@ -66,7 +67,7 @@ public class CmsState implements NodeState { availableSince = System.currentTimeMillis(); if (log.isDebugEnabled()) - log.debug("## CMS STARTED " + this.stateUuid + (cleanState ? " (clean state) " : " ")); + log.debug("## CMS starting... stateUuid=" + this.stateUuid + (cleanState ? " (clean state) " : " ")); initI18n(); initServices(); @@ -90,7 +91,7 @@ public class CmsState implements NodeState { // JCR RepositoryServiceFactory repositoryServiceFactory = new RepositoryServiceFactory(); - shutdownHooks.add(() -> repositoryServiceFactory.shutdown()); + stopHooks.add(() -> repositoryServiceFactory.shutdown()); bc.registerService(ManagedServiceFactory.class, repositoryServiceFactory, LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_REPOS_FACTORY_PID)); @@ -99,7 +100,7 @@ public class CmsState implements NodeState { // Security NodeUserAdmin userAdmin = new NodeUserAdmin(NodeConstants.ROLES_BASEDN); - shutdownHooks.add(() -> userAdmin.destroy()); + stopHooks.add(() -> userAdmin.destroy()); bc.registerService(ManagedServiceFactory.class, userAdmin, LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID)); @@ -132,7 +133,7 @@ public class CmsState implements NodeState { tmConf.setLogPart2Filename(new File(tmDir2, tmDir2.getName() + ".tlog").getAbsolutePath()); } BitronixTransactionManager transactionManager = getTransactionManager(); - shutdownHooks.add(() -> transactionManager.shutdown()); + stopHooks.add(() -> transactionManager.shutdown()); BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry = getTransactionSynchronizationRegistry(); // register bc.registerService(TransactionManager.class, transactionManager, null); @@ -143,20 +144,22 @@ public class CmsState implements NodeState { } void shutdown() { + if (log.isDebugEnabled()) + log.debug("CMS stopping... stateUuid=" + this.stateUuid + (cleanState ? " (clean state) " : " ")); + if (kernelThread != null) kernelThread.destroyAndJoin(); + applyStopHooks(); - applyShutdownHooks(); - - if (log.isDebugEnabled()) - log.debug("## CMS STOPPED"); + long duration = ((System.currentTimeMillis() - availableSince) / 1000) / 60; + log.info("## ARGEO CMS STOPPED after " + (duration / 60) + "h " + (duration % 60) + "min uptime ##"); } /** Apply shutdown hoos in reverse order. */ - private void applyShutdownHooks() { - for (int i = shutdownHooks.size() - 1; i >= 0; i--) { + private void applyStopHooks() { + for (int i = stopHooks.size() - 1; i >= 0; i--) { try { - shutdownHooks.get(i).run(); + stopHooks.get(i).run(); } catch (Exception e) { log.error("Could not run shutdown hook #" + i); } @@ -189,62 +192,4 @@ public class CmsState implements NodeState { public String getHostname() { return hostname; } - - /** Workaround for blocking Gogo shell by system shutdown. */ - private class GogoShellKiller extends Thread { - - public GogoShellKiller() { - super("Gogo Shell Killer"); - setDaemon(true); - } - - @Override - public void run() { - ThreadGroup rootTg = getRootThreadGroup(null); - Thread gogoShellThread = findGogoShellThread(rootTg); - if (gogoShellThread == null) - return; - while (getNonDaemonCount(rootTg) > 2) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - // silent - } - } - gogoShellThread = findGogoShellThread(rootTg); - if (gogoShellThread == null) - return; - System.exit(0); - } - } - - private static ThreadGroup getRootThreadGroup(ThreadGroup tg) { - if (tg == null) - tg = Thread.currentThread().getThreadGroup(); - if (tg.getParent() == null) - return tg; - else - return getRootThreadGroup(tg.getParent()); - } - - private static int getNonDaemonCount(ThreadGroup rootThreadGroup) { - Thread[] threads = new Thread[rootThreadGroup.activeCount()]; - rootThreadGroup.enumerate(threads); - int nonDameonCount = 0; - for (Thread t : threads) - if (t != null && !t.isDaemon()) - nonDameonCount++; - return nonDameonCount; - } - - private static Thread findGogoShellThread(ThreadGroup rootThreadGroup) { - Thread[] threads = new Thread[rootThreadGroup.activeCount()]; - rootThreadGroup.enumerate(threads, true); - for (Thread thread : threads) { - if (thread.getName().equals("Gogo shell")) - return thread; - } - return null; - } - } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInit.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInit.java index 78eb68289..1c7cb1497 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInit.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInit.java @@ -75,7 +75,7 @@ class FirstInit { if (keyStorePassword == null) keyStorePassword = "changeit"; if (!Files.exists(keyStorePath)) - createSelfSignedKeyStore(keyStorePath); + createSelfSignedKeyStore(keyStorePath, keyStorePassword); props.put(JettyConstants.SSL_KEYSTORETYPE, "PKCS12"); props.put(JettyConstants.SSL_KEYSTORE, keyStorePath.toString()); props.put(JettyConstants.SSL_PASSWORD, keyStorePassword); @@ -115,18 +115,18 @@ class FirstInit { // Business roles String userAdminUris = getFrameworkProp(NodeConstants.USERADMIN_URIS); if (userAdminUris == null) { - String demoBaseDn = "dc=example,dc=com"; - File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif"); - if (!businessRolesFile.exists()) - try { - FileUtils.copyInputStreamToFile(getClass().getResourceAsStream(demoBaseDn + ".ldif"), - businessRolesFile); - } catch (IOException e) { - throw new CmsException("Cannot copy demo resource", e); - } - userAdminUris = businessRolesFile.toURI().toString(); - log.warn("## DEV Using dummy base DN " + demoBaseDn); - // TODO downgrade security level + String demoBaseDn = "dc=example,dc=com"; + File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif"); + if (!businessRolesFile.exists()) + try { + FileUtils.copyInputStreamToFile(getClass().getResourceAsStream(demoBaseDn + ".ldif"), + businessRolesFile); + } catch (IOException e) { + throw new CmsException("Cannot copy demo resource", e); + } + userAdminUris = businessRolesFile.toURI().toString(); + log.warn("## DEV Using dummy base DN " + demoBaseDn); + // TODO downgrade security level } for (String userAdminUri : userAdminUris.split(" ")) uris.add(userAdminUri); @@ -158,10 +158,10 @@ class FirstInit { return res; } - + /** - * Called before node initialisation, in order populate OSGi instance are - * with some files (typically LDIF, etc). + * Called before node initialisation, in order populate OSGi instance are with + * some files (typically LDIF, etc). */ static void prepareInstanceArea() { String nodeInit = getFrameworkProp(NodeConstants.NODE_INIT); @@ -196,11 +196,11 @@ class FirstInit { } } - private void createSelfSignedKeyStore(Path keyStorePath) { + private void createSelfSignedKeyStore(Path keyStorePath, String keyStorePassword) { // for (Provider provider : Security.getProviders()) // System.out.println(provider.getName()); File keyStoreFile = keyStorePath.toFile(); - char[] ksPwd = "changeit".toCharArray(); + char[] ksPwd = keyStorePassword.toCharArray(); char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length); if (!keyStoreFile.exists()) { try { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/GogoShellKiller.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/GogoShellKiller.java new file mode 100644 index 000000000..940fc8d9f --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/GogoShellKiller.java @@ -0,0 +1,64 @@ +package org.argeo.cms.internal.kernel; + +/** + * Workaround for killing Gogo shell by system shutdown. + * + * @see https://issues.apache.org/jira/browse/FELIX-4208 + */ +class GogoShellKiller extends Thread { + + public GogoShellKiller() { + super("Gogo Shell Killer"); + setDaemon(true); + } + + @Override + public void run() { + ThreadGroup rootTg = getRootThreadGroup(null); + Thread gogoShellThread = findGogoShellThread(rootTg); + if (gogoShellThread == null) + return; + while (getNonDaemonCount(rootTg) > 2) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // silent + } + } + gogoShellThread = findGogoShellThread(rootTg); + if (gogoShellThread == null) + return; + // No non-deamon threads left, forcibly halting the VM + Runtime.getRuntime().halt(0); + } + + private ThreadGroup getRootThreadGroup(ThreadGroup tg) { + if (tg == null) + tg = Thread.currentThread().getThreadGroup(); + if (tg.getParent() == null) + return tg; + else + return getRootThreadGroup(tg.getParent()); + } + + private int getNonDaemonCount(ThreadGroup rootThreadGroup) { + Thread[] threads = new Thread[rootThreadGroup.activeCount()]; + rootThreadGroup.enumerate(threads); + int nonDameonCount = 0; + for (Thread t : threads) + if (t != null && !t.isDaemon()) + nonDameonCount++; + return nonDameonCount; + } + + private Thread findGogoShellThread(ThreadGroup rootThreadGroup) { + Thread[] threads = new Thread[rootThreadGroup.activeCount()]; + rootThreadGroup.enumerate(threads, true); + for (Thread thread : threads) { + if (thread.getName().equals("Gogo shell")) + return thread; + } + return null; + } + +} \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java index 14d88144d..e83d6c10e 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java @@ -156,18 +156,25 @@ class NodeLogger implements ArgeoLogger, LogListener { if (sr != null) { sb.append(' '); String[] objectClasses = (String[]) sr.getProperty(Constants.OBJECTCLASS); - sb.append(arrayToString(objectClasses)); + if (isSpringApplicationContext(objectClasses)) { + sb.append("{org.springframework.context.ApplicationContext}"); + Object symbolicName = sr.getProperty(Constants.BUNDLE_SYMBOLICNAME); + if (symbolicName != null) + sb.append(" " + Constants.BUNDLE_SYMBOLICNAME + ": " + symbolicName); + } else { + sb.append(arrayToString(objectClasses)); + } Object cn = sr.getProperty(NodeConstants.CN); if (cn != null) sb.append(" " + NodeConstants.CN + ": " + cn); Object factoryPid = sr.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID); if (factoryPid != null) sb.append(" " + ConfigurationAdmin.SERVICE_FACTORYPID + ": " + factoryPid); -// else { -// Object servicePid = sr.getProperty(Constants.SERVICE_PID); -// if (servicePid != null) -// sb.append(" " + Constants.SERVICE_PID + ": " + servicePid); -// } + // else { + // Object servicePid = sr.getProperty(Constants.SERVICE_PID); + // if (servicePid != null) + // sb.append(" " + Constants.SERVICE_PID + ": " + servicePid); + // } // servlets Object whiteBoardPattern = sr.getProperty(KernelConstants.WHITEBOARD_PATTERN_PROP); if (whiteBoardPattern != null) @@ -177,11 +184,12 @@ class NodeLogger implements ArgeoLogger, LogListener { Object contextName = sr.getProperty(KernelConstants.CONTEXT_NAME_PROP); if (contextName != null) sb.append(" " + KernelConstants.CONTEXT_NAME_PROP + ": " + contextName); - + // user directories Object baseDn = sr.getProperty(UserAdminConf.baseDn.name()); if (baseDn != null) sb.append(" " + UserAdminConf.baseDn.name() + ": " + baseDn); + } return sb.toString(); } @@ -198,6 +206,15 @@ class NodeLogger implements ArgeoLogger, LogListener { return sb.toString(); } + private boolean isSpringApplicationContext(String[] objectClasses) { + for (String clss : objectClasses) { + if (clss.equals("org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext")) { + return true; + } + } + return false; + } + // // ARGEO LOGGER //