Improve node deployment
authormbaudier <mbaudier@mostar>
Thu, 2 Nov 2017 14:48:31 +0000 (15:48 +0100)
committermbaudier <mbaudier@mostar>
Thu, 2 Nov 2017 14:48:31 +0000 (15:48 +0100)
14 files changed:
dist/argeo-node/pom.xml
dist/argeo-node/rpm/etc/node/config.ini
dist/argeo-node/rpm/etc/node/log4j.properties
dist/argeo-node/rpm/usr/lib/systemd/system/node.service
dist/argeo-node/rpm/usr/sbin/node-service [deleted file]
dist/argeo-node/rpm/usr/sbin/nodectl [new file with mode: 0755]
org.argeo.cms.ui/src/org/argeo/cms/util/SimpleUxContext.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsShutdown.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInit.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/GogoShellKiller.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java

index e53a115ce1d8ee1a7e51fc261e1e67e24442a852..da4e2294996969f358c61f8d87d4f807f3ce7568 100644 (file)
@@ -65,7 +65,7 @@
                                                                                                <source>
                                                                                                        <location>rpm/usr/sbin</location>
                                                                                                        <includes>
-                                                                                                               <include>node-service</include>
+                                                                                                               <include>nodectl</include>
                                                                                                        </includes>
                                                                                                </source>
                                                                                        </sources>
index 44a2170e593346c6d8da9ad2289a0aa524b3510b..ec75a4f7a507b1879da9dda5f3f6018908728f45 100644 (file)
@@ -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,\
index f79dc2c6bfdc77ea72d47f0f58757df31f66c078..d53b851de61dd1c5e4cad41615c3d93f851d1aed 100644 (file)
@@ -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
index 45fab9ada88b2486619f09cd9ff7a3961cdc5022..80cd827a1cfddcbd26b17569f0cb2565a33d577b 100644 (file)
@@ -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 (executable)
index 7accca9..0000000
+++ /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 (executable)
index 0000000..26fe3ee
--- /dev/null
@@ -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
index a3844465800ad659604c5493f09ef2cde377a97f..bde67e4045fc8177900e96e3d9af42d229e5aa19 100644 (file)
@@ -43,7 +43,8 @@ public class SimpleUxContext implements UxContext {
 
        @Override
        public boolean isMasterData() {
-               return false;
+               // TODO make it configurable
+               return true;
        }
 
 }
index a70235976ee8c34b1ba4d7891b2e1b1a3dc4835c..1efc9dc66474953221194974c0044558e163514b 100644 (file)
@@ -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);
index 126c591e64befe548823d048b6ad33236b56efee..07c10f486045f64d0d7adf120367b2af08a93c13 100644 (file)
@@ -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 (file)
index 0000000..a62ee7f
--- /dev/null
@@ -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);
+               }
+       }
+
+}
index eebf71ccbb4c3df4f0abbf2cf724b6681eb62874..0b5bd0d483440a13bed946e06d944a850af1e098 100644 (file)
@@ -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<Runnable> shutdownHooks = new ArrayList<>();
+       private List<Runnable> 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;
-       }
-
 }
index 78eb68289647de357e15ac70c8a1df8aeef0696e..1c7cb149752a7c30ce6b56da3ad1f9db8da21929 100644 (file)
@@ -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 (file)
index 0000000..940fc8d
--- /dev/null
@@ -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
index 14d88144d1053df6b360dfa4d791f95cd7575998..e83d6c10ed9cd42c7af5da29b4ff05425b1229dc 100644 (file)
@@ -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
        //