Stabilise deployment
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 6 Sep 2016 08:19:14 +0000 (08:19 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 6 Sep 2016 08:19:14 +0000 (08:19 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@9090 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

demo/log4j.properties
org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java
org.argeo.cms.api/src/org/argeo/node/NodeState.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/CmsInstance.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/DeployConfig.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java

index 94c48c3d771400cfb88305605e6705eba91b49f9..a3854b0c131f47b2a92b0c3b702c3d30c707f789 100644 (file)
@@ -2,9 +2,6 @@ log4j.rootLogger=WARN, console
 
 log4j.logger.org.argeo=DEBUG
 log4j.logger.org.argeo.cms.internal.kernel=TRACE
-#log4j.logger.org.apache.jackrabbit.core.RepositoryImpl=DEBUG
-#log4j.logger.argeo.stats=DEBUG
-#log4j.logger.org.eclipse.jetty.server.Server=DEBUG
 
 ## Appenders
 log4j.appender.console=org.apache.log4j.ConsoleAppender
index 1b04d68098b8517388b5495cfed6e5b3fb36e3ae..8e5558d608faec63b9b0c344fb570683a6d7c3db 100644 (file)
@@ -1,5 +1,5 @@
 package org.argeo.node;
 
 public interface NodeDeployment {
-       long getAvailableSince();
+       Long getAvailableSince();
 }
index 7568cd95b8402dacb39f9d6486981cc73e6cb2b2..d7148c68ff1a479f59dff703047f31076d922d2e 100644 (file)
@@ -11,4 +11,7 @@ public interface NodeState {
        String getHostname();
 
        boolean isClean();
+       
+       Long getAvailableSince();
+
 }
index 6aacfd4931760f6e9c85f8d1724f35cfccf55dca..ecd36476facdd5cbc7e187cb87dd0c01d84b840e 100644 (file)
@@ -2,8 +2,9 @@ package org.argeo.cms.internal.kernel;
 
 import java.io.IOException;
 import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Dictionary;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Locale;
 
@@ -13,15 +14,13 @@ import org.argeo.cms.CmsException;
 import org.argeo.node.ArgeoLogger;
 import org.argeo.node.NodeConstants;
 import org.argeo.node.NodeDeployment;
+import org.argeo.node.NodeInstance;
 import org.argeo.node.NodeState;
 import org.argeo.util.LangUtils;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ManagedService;
 import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
 import org.osgi.service.log.LogReaderService;
 
@@ -30,45 +29,36 @@ import org.osgi.service.log.LogReaderService;
  * access to kernel information for the rest of the bundle (and only it)
  */
 public class Activator implements BundleActivator {
-       // public final static String SYSTEM_KEY_PROPERTY =
-       // "argeo.security.systemKey";
        private final Log log = LogFactory.getLog(Activator.class);
 
-       // private final static String systemKey;
-       // static {
-       // System.setProperty(SYSTEM_KEY_PROPERTY, systemKey);
-       // }
-
-       // private static Kernel kernel;
        private static Activator instance;
 
        private BundleContext bc;
        private ConditionalPermissionAdmin permissionAdmin;
        private LogReaderService logReaderService;
-       private ConfigurationAdmin configurationAdmin;
+       // private ConfigurationAdmin configurationAdmin;
 
        private NodeLogger logger;
        private CmsState nodeState;
        private CmsDeployment nodeDeployment;
+       private CmsInstance nodeInstance;
 
        @Override
        public void start(BundleContext bundleContext) throws Exception {
-               // try {
-               // kernel = new Kernel();
-               // kernel.init();
-               // } catch (Exception e) {
-               // log.error("Cannot boot kernel", e);
-               // }
-
                instance = this;
                this.bc = bundleContext;
                this.permissionAdmin = getService(ConditionalPermissionAdmin.class);
                this.logReaderService = getService(LogReaderService.class);
-               this.configurationAdmin = getService(ConfigurationAdmin.class);
+               // this.configurationAdmin = getService(ConfigurationAdmin.class);
 
                initSecurity();// must be first
                initArgeoLogger();
-               initNodeState();
+               try {
+                       initNode();
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new CmsException("Cannot initialize node", e);
+               }
        }
 
        private void initSecurity() {
@@ -78,74 +68,61 @@ public class Activator implements BundleActivator {
 
        private void initArgeoLogger() {
                logger = new NodeLogger(logReaderService);
-
-               // register
                bc.registerService(ArgeoLogger.class, logger, null);
        }
 
-       private void initNodeState() throws IOException {
-               nodeState = new CmsState();
-
-               Object cn;
-               Configuration nodeConf = configurationAdmin.getConfiguration(NodeConstants.NODE_STATE_PID);
-               Dictionary<String, Object> props = nodeConf.getProperties();
-               if (props == null) {
-                       if (log.isDebugEnabled())
-                               log.debug("Clean node state");
-                       Dictionary<String, Object> envProps = new Hashtable<>();
-                       // Use the UUID of the first framework run as state UUID
-                       cn = bc.getProperty(Constants.FRAMEWORK_UUID);
-                       envProps.put(NodeConstants.CN, cn);
-                       nodeConf.update(envProps);
+       private void initNode() throws IOException {
+               // Node state
+               Path stateUuidPath = bc.getDataFile("stateUuid").toPath();
+               String stateUuid;
+               if (Files.exists(stateUuidPath)) {
+                       stateUuid = Files.readAllLines(stateUuidPath).get(0);
                } else {
-                       // Check if state is in line with environment
-                       // Dictionary<String, Object> envProps = new Hashtable<>();
-                       // for (String key : LangUtils.keys(envProps)) {
-                       // Object envValue = envProps.get(key);
-                       // Object storedValue = props.get(key);
-                       // if (storedValue == null)
-                       // throw new CmsException("No state value for env " + key + "=" +
-                       // envValue
-                       // + ", please clean the OSGi configuration.");
-                       // if (!storedValue.equals(envValue))
-                       // throw new CmsException("State value for " + key + "=" +
-                       // storedValue
-                       // + " is different from env value =" + envValue + ", please clean
-                       // the OSGi configuration.");
-                       // }
-                       cn = props.get(NodeConstants.CN);
-                       if (cn == null)
-                               throw new CmsException("No state UUID available");
+                       stateUuid = bc.getProperty(Constants.FRAMEWORK_UUID);
+                       Files.write(stateUuidPath, stateUuid.getBytes());
                }
-
+               nodeState = new CmsState(stateUuid);
+               // Object cn;
+               // Configuration nodeConf =
+               // configurationAdmin.getConfiguration(NodeConstants.NODE_STATE_PID);
+               // Dictionary<String, Object> props = nodeConf.getProperties();
+               // if (props == null) {
+               // if (log.isDebugEnabled())
+               // log.debug("Clean node state");
+               // Dictionary<String, Object> envProps = new Hashtable<>();
+               // // Use the UUID of the first framework run as state UUID
+               // cn = bc.getProperty(Constants.FRAMEWORK_UUID);
+               // envProps.put(NodeConstants.CN, cn);
+               // nodeConf.update(envProps);
+               // } else {
+               // cn = props.get(NodeConstants.CN);
+               // if (cn == null)
+               // throw new CmsException("No state UUID available");
+               // }
                Dictionary<String, Object> regProps = LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID);
-               regProps.put(NodeConstants.CN, cn);
-               bc.registerService(LangUtils.names(NodeState.class, ManagedService.class), nodeState, regProps);
+               regProps.put(NodeConstants.CN, stateUuid);
+               bc.registerService(NodeState.class, nodeState, regProps);
 
-               try {
-                       nodeDeployment = new CmsDeployment();
-                       bc.registerService(LangUtils.names(NodeDeployment.class), nodeDeployment, null);
-               } catch (RuntimeException e) {
-                       e.printStackTrace();
-                       throw e;
-               }
+               // Node deployment
+               nodeDeployment = new CmsDeployment();
+               bc.registerService(NodeDeployment.class, nodeDeployment, null);
+
+               // Node instance
+               nodeInstance = new CmsInstance();
+               bc.registerService(NodeInstance.class, nodeInstance, null);
        }
 
        @Override
        public void stop(BundleContext bundleContext) throws Exception {
+               nodeInstance.shutdown();
+               nodeDeployment.shutdown();
                nodeState.shutdown();
 
                instance = null;
                this.bc = null;
                this.permissionAdmin = null;
                this.logReaderService = null;
-               this.configurationAdmin = null;
-
-               // if (kernel != null) {
-               // kernel.destroy();
-               // kernel = null;
-               // }
-
+               // this.configurationAdmin = null;
        }
 
        private <T> T getService(Class<T> clazz) {
index 724108fb198c6c3d963b806c81309a955046d85f..45e218a15701e9e3b00c1ae8619350566389f68c 100644 (file)
@@ -2,30 +2,18 @@ package org.argeo.cms.internal.kernel;
 
 import static org.argeo.node.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.io.Writer;
+import java.lang.management.ManagementFactory;
 import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Dictionary;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
 
 import javax.jcr.Repository;
 import javax.jcr.Session;
-import javax.naming.InvalidNameException;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -38,9 +26,6 @@ import org.argeo.node.DataModelNamespace;
 import org.argeo.node.NodeConstants;
 import org.argeo.node.NodeDeployment;
 import org.argeo.node.NodeState;
-import org.argeo.util.naming.AttributesDictionary;
-import org.argeo.util.naming.LdifParser;
-import org.argeo.util.naming.LdifWriter;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
@@ -48,29 +33,82 @@ import org.osgi.framework.ServiceReference;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ConfigurationEvent;
-import org.osgi.service.cm.SynchronousConfigurationListener;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.useradmin.UserAdmin;
 import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
 public class CmsDeployment implements NodeDeployment {
        private final Log log = LogFactory.getLog(getClass());
        private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
 
        private final DeployConfig deployConfig;
-       // private Repository deployedNodeRepository;
        private HomeRepository homeRepository;
 
        private Long availableSince;
 
+       // Readiness
+       private boolean nodeAvailable = false;
+       private boolean userAdminAvailable = false;
+       private boolean httpExpected = false;
+       private boolean httpAvailable = false;
+
        public CmsDeployment() {
-               // FIXME no guarantee this is already available
-               NodeState nodeState = bc.getService(bc.getServiceReference(NodeState.class));
+               ServiceReference<NodeState> nodeStateSr = bc.getServiceReference(NodeState.class);
+               if (nodeStateSr == null)
+                       throw new CmsException("No node state available");
+
+               NodeState nodeState = bc.getService(nodeStateSr);
                deployConfig = new DeployConfig(nodeState.isClean());
+               httpExpected = deployConfig.getProps(KernelConstants.JETTY_FACTORY_PID, "default") != null;
+
+               initTrackers();
+       }
+
+       private void initTrackers() {
+               new PrepareHttpStc().open();
+               new RepositoryContextStc().open();
+               new ServiceTracker<UserAdmin, UserAdmin>(bc, UserAdmin.class, null) {
+                       @Override
+                       public UserAdmin addingService(ServiceReference<UserAdmin> reference) {
+                               userAdminAvailable = true;
+                               checkReadiness();
+                               return super.addingService(reference);
+                       }
+               }.open();
+       }
+
+       public void shutdown() {
+               deployConfig.save();
+       }
 
-               new ServiceTracker<>(bc, RepositoryContext.class, new RepositoryContextStc()).open();
+       private void checkReadiness() {
+               if (nodeAvailable && userAdminAvailable && (httpExpected ? httpAvailable : true)) {
+                       availableSince = System.currentTimeMillis();
+                       long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
+                       log.info("## ARGEO CMS AVAILABLE in " + (jvmUptime / 1000) + "." + (jvmUptime % 1000) + "s ##");
+                       long begin = bc.getService(bc.getServiceReference(NodeState.class)).getAvailableSince();
+                       long initDuration = System.currentTimeMillis() - begin;
+                       if (log.isTraceEnabled())
+                               log.trace("Kernel initialization took " + initDuration + "ms");
+                       directorsCut(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
+               }
+               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) {
@@ -78,8 +116,6 @@ public class CmsDeployment implements NodeDeployment {
                        throw new CmsException("Deployment is already available");
                }
 
-               availableSince = System.currentTimeMillis();
-
                prepareDataModel(KernelUtils.openAdminSession(deployedNodeRepository));
                Hashtable<String, String> regProps = new Hashtable<String, String>();
                regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_HOME);
@@ -140,22 +176,22 @@ public class CmsDeployment implements NodeDeployment {
 
                Hashtable<String, Object> properties = new Hashtable<>();
                properties.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, name);
+               properties.put(NodeConstants.CN, name);
                bc.registerService(Repository.class, adminSession.getRepository(), properties);
                if (log.isDebugEnabled())
                        log.debug("Published data model " + name);
        }
 
-       // public void setDeployedNodeRepository(Repository deployedNodeRepository)
-       // {
-       // this.deployedNodeRepository = deployedNodeRepository;
-       // }
-
        @Override
-       public long getAvailableSince() {
+       public Long getAvailableSince() {
                return availableSince;
        }
 
-       private class RepositoryContextStc implements ServiceTrackerCustomizer<RepositoryContext, RepositoryContext> {
+       private class RepositoryContextStc extends ServiceTracker<RepositoryContext, RepositoryContext> {
+
+               public RepositoryContextStc() {
+                       super(bc, RepositoryContext.class, null);
+               }
 
                @Override
                public RepositoryContext addingService(ServiceReference<RepositoryContext> reference) {
@@ -163,17 +199,9 @@ public class CmsDeployment implements NodeDeployment {
                        Object cn = reference.getProperty(NodeConstants.CN);
                        if (cn != null && cn.equals(ArgeoJcrConstants.ALIAS_NODE)) {
                                prepareNodeRepository(nodeRepo.getRepository());
-                               // nodeDeployment.setDeployedNodeRepository(nodeRepo.getRepository());
-                               // Dictionary<String, Object> props =
-                               // LangUtils.init(Constants.SERVICE_PID,
-                               // NodeConstants.NODE_DEPLOYMENT_PID);
-                               // props.put(NodeConstants.CN,
-                               // nodeRepo.getRootNodeId().toString());
-                               // register
-                               // bc.registerService(LangUtils.names(NodeDeployment.class,
-                               // ManagedService.class), nodeDeployment, props);
+                               nodeAvailable = true;
+                               checkReadiness();
                        }
-
                        return nodeRepo;
                }
 
@@ -187,4 +215,46 @@ public class CmsDeployment implements NodeDeployment {
 
        }
 
+       private class PrepareHttpStc extends ServiceTracker<HttpService, HttpService> {
+               private DataHttp dataHttp;
+               private NodeHttp nodeHttp;
+
+               public PrepareHttpStc() {
+                       super(bc, HttpService.class, null);
+               }
+
+               @Override
+               public HttpService addingService(ServiceReference<HttpService> reference) {
+                       HttpService httpService = addHttpService(reference);
+                       return httpService;
+               }
+
+               @Override
+               public void removedService(ServiceReference<HttpService> reference, HttpService service) {
+                       if (dataHttp != null)
+                               dataHttp.destroy();
+                       dataHttp = null;
+                       if (nodeHttp != null)
+                               nodeHttp.destroy();
+                       nodeHttp = null;
+               }
+
+               private HttpService addHttpService(ServiceReference<HttpService> sr) {
+                       HttpService httpService = bc.getService(sr);
+                       // TODO find constants
+                       Object httpPort = sr.getProperty("http.port");
+                       Object httpsPort = sr.getProperty("https.port");
+                       dataHttp = new DataHttp(httpService);
+                       nodeHttp = new NodeHttp(httpService, bc);
+                       log.info(httpPortsMsg(httpPort, httpsPort));
+                       httpAvailable = true;
+                       checkReadiness();
+                       return httpService;
+               }
+
+               private String httpPortsMsg(Object httpPort, Object httpsPort) {
+                       return "HTTP " + httpPort + (httpsPort != null ? " - HTTPS " + httpsPort : "");
+               }
+       }
+
 }
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java
new file mode 100644 (file)
index 0000000..795f063
--- /dev/null
@@ -0,0 +1,43 @@
+package org.argeo.cms.internal.kernel;
+
+import javax.jcr.Repository;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.node.NodeConstants;
+import org.argeo.node.NodeInstance;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class CmsInstance implements NodeInstance {
+       private final Log log = LogFactory.getLog(getClass());
+       private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
+
+
+       public CmsInstance() {
+               initTrackers();
+       }
+
+       private void initTrackers() {
+               // node repository
+               new ServiceTracker<Repository, Repository>(bc, Repository.class, null) {
+                       @Override
+                       public Repository addingService(ServiceReference<Repository> reference) {
+                               Object cn = reference.getProperty(NodeConstants.CN);
+                               if (cn != null && cn.equals(ArgeoJcrConstants.ALIAS_NODE)) {
+                                       if (log.isDebugEnabled())
+                                               log.debug("Node repository is available");
+                               }
+                               return super.addingService(reference);
+                       }
+               }.open();
+       }
+
+       public void shutdown() {
+
+       }
+
+}
index f8073c46ff984b9ed5c3735baf512b8ff24ae3f0..23d2f266d89325c71dc99bc168498340049b37ab 100644 (file)
@@ -4,145 +4,80 @@ import static bitronix.tm.TransactionManagerServices.getTransactionManager;
 import static bitronix.tm.TransactionManagerServices.getTransactionSynchronizationRegistry;
 import static java.util.Locale.ENGLISH;
 import static org.argeo.cms.internal.auth.LocaleChoice.asLocaleList;
-import static org.argeo.cms.internal.kernel.KernelUtils.getFrameworkProp;
 
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
 import java.net.InetAddress;
-import java.net.URI;
 import java.net.UnknownHostException;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Dictionary;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Locale;
-import java.util.SortedMap;
 import java.util.UUID;
 
 import javax.jcr.RepositoryFactory;
-import javax.naming.InvalidNameException;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
 import javax.transaction.TransactionManager;
 import javax.transaction.TransactionSynchronizationRegistry;
 import javax.transaction.UserTransaction;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.jackrabbit.core.RepositoryContext;
-import org.argeo.cms.CmsException;
 import org.argeo.cms.maintenance.MaintenanceUi;
-import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeDeployment;
 import org.argeo.node.NodeState;
-import org.argeo.node.RepoConf;
 import org.argeo.util.LangUtils;
-import org.argeo.util.naming.AttributesDictionary;
-import org.argeo.util.naming.LdifParser;
-import org.eclipse.equinox.http.jetty.JettyConfigurator;
-import org.eclipse.equinox.http.jetty.JettyConstants;
 import org.eclipse.rap.rwt.application.ApplicationConfiguration;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
 import org.osgi.service.cm.ManagedServiceFactory;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.metatype.MetaTypeProvider;
 import org.osgi.service.useradmin.UserAdmin;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
 import bitronix.tm.BitronixTransactionManager;
 import bitronix.tm.BitronixTransactionSynchronizationRegistry;
 import bitronix.tm.TransactionManagerServices;
 
-public class CmsState implements NodeState, ManagedService {
+public class CmsState implements NodeState {
        private final Log log = LogFactory.getLog(CmsState.class);
        private final BundleContext bc = FrameworkUtil.getBundle(CmsState.class).getBundleContext();
 
-       // avoid dependency to RWT OSGi
-       private final static String PROPERTY_CONTEXT_NAME = "contextName";
-
        // REFERENCES
-       private ConfigurationAdmin configurationAdmin;
+       private Long availableSince;
 
        // i18n
        private Locale defaultLocale;
        private List<Locale> locales = null;
 
-       // private BitronixTransactionManager transactionManager;
-       // private BitronixTransactionSynchronizationRegistry
-       // transactionSynchronizationRegistry;
-       // private NodeRepositoryFactory repositoryFactory;
-       // private NodeUserAdmin userAdmin;
-       // private RepositoryServiceFactory repositoryServiceFactory;
-       // private RepositoryService repositoryService;
-
-       // Deployment
-       // private final CmsDeployment nodeDeployment = new CmsDeployment();
-
-       private boolean cleanState = false;
-       private URI nodeRepoUri = null;
-
        private ThreadGroup threadGroup = new ThreadGroup("CMS");
        private KernelThread kernelThread;
        private List<Runnable> shutdownHooks = new ArrayList<>();
 
+       private final String stateUuid;
+       private final boolean cleanState;
        private String hostname;
 
-       public CmsState() {
+       public CmsState(String stateUuid) {
+               this.stateUuid = stateUuid;
+               String frameworkUuid = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID);
+               this.cleanState = stateUuid.equals(frameworkUuid);
                try {
                        this.hostname = InetAddress.getLocalHost().getHostName();
                } catch (UnknownHostException e) {
                        log.error("Cannot set hostname", e);
                }
-       }
 
-       @Override
-       public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
-               if (properties == null) {
-                       // // TODO this should not happen anymore
-                       // this.cleanState = true;
-                       // if (log.isTraceEnabled())
-                       // log.trace("Clean state");
-                       return;
-               }
-               String stateUuid = properties.get(NodeConstants.CN).toString();
-               String frameworkUuid = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID);
-               this.cleanState = stateUuid.equals(frameworkUuid);
+               availableSince = System.currentTimeMillis();
+               if (log.isDebugEnabled())
+                       log.debug("## CMS STARTED " + this.stateUuid + (cleanState ? " (clean state) " : " "));
 
-               try {
-                       if (log.isDebugEnabled())
-                               log.debug("## CMS STARTED " + stateUuid + (cleanState ? " (clean state) " : " ")
-                                               + LangUtils.toJson(properties, true));
-                       configurationAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
-
-                       nodeRepoUri = KernelUtils.getOsgiInstanceUri("repos/node");
-
-                       initI18n();
-                       initServices();
-//                     initDeployConfigs();
-                       // initWebServer();
-                       // initNodeDeployment();
-
-                       // kernel thread
-                       kernelThread = new KernelThread(threadGroup, "Kernel Thread");
-                       kernelThread.setContextClassLoader(getClass().getClassLoader());
-                       kernelThread.start();
-               } catch (Exception e) {
-                       throw new CmsException("Cannot get configuration", e);
-               }
+               initI18n();
+               initServices();
+
+               // kernel thread
+               kernelThread = new KernelThread(threadGroup, "Kernel Thread");
+               kernelThread.setContextClassLoader(getClass().getClassLoader());
+               kernelThread.start();
        }
 
        private void initI18n() {
@@ -153,9 +88,6 @@ public class CmsState implements NodeState, ManagedService {
        }
 
        private void initServices() {
-               // trackers
-               new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, new PrepareHttpStc()).open();
-
                initTransactionManager();
 
                // JCR
@@ -167,12 +99,6 @@ public class CmsState implements NodeState, ManagedService {
                NodeRepositoryFactory repositoryFactory = new NodeRepositoryFactory();
                bc.registerService(RepositoryFactory.class, repositoryFactory, null);
 
-               // RepositoryService repositoryService = new RepositoryService();
-               // shutdownHooks.add(() -> repositoryService.shutdown());
-               // bc.registerService(LangUtils.names(ManagedService.class,
-               // MetaTypeProvider.class), repositoryService,
-               // LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID));
-
                // Security
                NodeUserAdmin userAdmin = new NodeUserAdmin();
                shutdownHooks.add(() -> userAdmin.destroy());
@@ -182,17 +108,9 @@ public class CmsState implements NodeState, ManagedService {
 
                // UI
                bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
-                               LangUtils.init(PROPERTY_CONTEXT_NAME, "system"));
-               bc.registerService(ApplicationConfiguration.class, new UserUi(), LangUtils.init(PROPERTY_CONTEXT_NAME, "user"));
+                               LangUtils.init(KernelConstants.CONTEXT_NAME_PROP, "system"));
+               bc.registerService(ApplicationConfiguration.class, new UserUi(), LangUtils.init(KernelConstants.CONTEXT_NAME_PROP, "user"));
        }
-       // private void initUserAdmin() {
-       // userAdmin = new NodeUserAdmin();
-       // // register
-       // Dictionary<String, Object> props = userAdmin.currentState();
-       // props.put(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID);
-       // // TODO use ManagedService
-       // bc.registerService(UserAdmin.class, userAdmin, props);
-       // }
 
        private void initTransactionManager() {
                // TODO manage it in a managed service, as startup could be long
@@ -224,49 +142,7 @@ public class CmsState implements NodeState, ManagedService {
                        log.debug("Initialised default Bitronix transaction manager");
        }
 
-       // private void initRepositoryFactory() {
-       // // TODO rationalise RepositoryFactory
-       // repositoryFactory = new NodeRepositoryFactory();
-       // // register
-       // bc.registerService(RepositoryFactory.class, repositoryFactory, null);
-       // }
-
-       // private void initUi() {
-       // bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
-       // LangUtils.init(PROPERTY_CONTEXT_NAME, "system"));
-       // bc.registerService(ApplicationConfiguration.class, new UserUi(),
-       // LangUtils.init(PROPERTY_CONTEXT_NAME, "user"));
-       // }
-
-       // private void initRepositories(Dictionary<String, ?> stateProps) throws
-       // IOException {
-       // // register
-       // repositoryServiceFactory = new RepositoryServiceFactory();
-       // bc.registerService(ManagedServiceFactory.class, repositoryServiceFactory,
-       // LangUtils.init(Constants.SERVICE_PID,
-       // NodeConstants.JACKRABBIT_FACTORY_PID));
-       //
-       // repositoryService = new RepositoryService();
-       // Dictionary<String, Object> regProps =
-       // LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID);
-       // bc.registerService(LangUtils.names(ManagedService.class,
-       // MetaTypeProvider.class), repositoryService, regProps);
-       // }
-
-       // private void initNodeDeployment() throws IOException {
-       // Configuration nodeDeploymentConf =
-       // configurationAdmin.getConfiguration(NodeConstants.NODE_DEPLOYMENT_PID);
-       // nodeDeploymentConf.update(new Hashtable<>());
-       // }
-
        void shutdown() {
-               // if (transactionManager != null)
-               // transactionManager.shutdown();
-               // if (userAdmin != null)
-               // userAdmin.destroy();
-               // if (repositoryServiceFactory != null)
-               // repositoryServiceFactory.shutdown();
-
                applyShutdownHooks();
 
                if (kernelThread != null)
@@ -280,8 +156,6 @@ public class CmsState implements NodeState, ManagedService {
        private void applyShutdownHooks() {
                for (int i = shutdownHooks.size() - 1; i >= 0; i--) {
                        try {
-                               // new Thread(shutdownHooks.get(i), "CMS Shutdown Hook #" +
-                               // i).start();
                                shutdownHooks.get(i).run();
                        } catch (Exception e) {
                                log.error("Could not run shutdown hook #" + i);
@@ -291,49 +165,16 @@ public class CmsState implements NodeState, ManagedService {
                new GogoShellKiller().start();
        }
 
-       private class PrepareHttpStc implements ServiceTrackerCustomizer<HttpService, HttpService> {
-               private DataHttp dataHttp;
-               private NodeHttp nodeHttp;
-
-               @Override
-               public HttpService addingService(ServiceReference<HttpService> reference) {
-                       HttpService httpService = addHttpService(reference);
-                       return httpService;
-               }
-
-               @Override
-               public void modifiedService(ServiceReference<HttpService> reference, HttpService service) {
-               }
-
-               @Override
-               public void removedService(ServiceReference<HttpService> reference, HttpService service) {
-                       if (dataHttp != null)
-                               dataHttp.destroy();
-                       dataHttp = null;
-                       if (nodeHttp != null)
-                               nodeHttp.destroy();
-                       nodeHttp = null;
-               }
-
-               private HttpService addHttpService(ServiceReference<HttpService> sr) {
-                       HttpService httpService = bc.getService(sr);
-                       // TODO find constants
-                       Object httpPort = sr.getProperty("http.port");
-                       Object httpsPort = sr.getProperty("https.port");
-                       dataHttp = new DataHttp(httpService);
-                       nodeHttp = new NodeHttp(httpService, bc);
-                       if (log.isDebugEnabled())
-                               log.debug(httpPortsMsg(httpPort, httpsPort));
-                       return httpService;
-               }
-
-       }
-
        @Override
        public boolean isClean() {
                return cleanState;
        }
 
+       @Override
+       public Long getAvailableSince() {
+               return availableSince;
+       }
+
        /*
         * ACCESSORS
         */
@@ -349,13 +190,6 @@ public class CmsState implements NodeState, ManagedService {
                return hostname;
        }
 
-       /*
-        * STATIC
-        */
-       private static String httpPortsMsg(Object httpPort, Object httpsPort) {
-               return "HTTP " + httpPort + (httpsPort != null ? " - HTTPS " + httpsPort : "");
-       }
-
        /** Workaround for blocking Gogo shell by system shutdown. */
        private class GogoShellKiller extends Thread {
 
index 376323aac0fbdc8c2ba49bee6eb6836e11e7a922..572631effec0487231da9dd0c4c6c114f06c60f5 100644 (file)
@@ -20,7 +20,6 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.node.NodeConstants;
-import org.argeo.node.NodeState;
 import org.argeo.util.naming.AttributesDictionary;
 import org.argeo.util.naming.LdifParser;
 import org.argeo.util.naming.LdifWriter;
@@ -29,9 +28,9 @@ import org.osgi.framework.FrameworkUtil;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.cm.ConfigurationEvent;
-import org.osgi.service.cm.SynchronousConfigurationListener;
+import org.osgi.service.cm.ConfigurationListener;
 
-class DeployConfig implements SynchronousConfigurationListener {
+class DeployConfig implements ConfigurationListener {
        private final Log log = LogFactory.getLog(getClass());
        private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
 
@@ -48,7 +47,8 @@ class DeployConfig implements SynchronousConfigurationListener {
                } catch (IOException e) {
                        throw new CmsException("Could not init deploy configs", e);
                }
-               bc.registerService(SynchronousConfigurationListener.class, this, null);
+               // FIXME check race conditions during initialization
+               // bc.registerService(ConfigurationListener.class, this, null);
        }
 
        private void firstInit() throws IOException {
@@ -74,7 +74,7 @@ class DeployConfig implements SynchronousConfigurationListener {
                if (!webServerConfig.isEmpty())
                        putFactoryDeployConfig(KernelConstants.JETTY_FACTORY_PID, webServerConfig);
 
-               saveDeployedConfigs();
+               save();
        }
 
        private void init(ConfigurationAdmin configurationAdmin, boolean isClean) throws IOException {
@@ -144,7 +144,7 @@ class DeployConfig implements SynchronousConfigurationListener {
                                                        assert attrs != null;
                                                        AttributesDictionary.copy(conf.getProperties(), attrs);
                                                }
-                                               saveDeployedConfigs();
+                                               save();
                                                if (log.isDebugEnabled())
                                                        log.debug("Updated deploy config " + serviceDn(factoryPid, cn.toString()));
                                        } else {
@@ -156,7 +156,7 @@ class DeployConfig implements SynchronousConfigurationListener {
                                                Attributes attrs = deployConfigs.get(serviceDn);
                                                assert attrs != null;
                                                AttributesDictionary.copy(conf.getProperties(), attrs);
-                                               saveDeployedConfigs();
+                                               save();
                                                if (log.isDebugEnabled())
                                                        log.debug("Updated deploy config " + serviceDn);
                                        } else {
@@ -189,9 +189,11 @@ class DeployConfig implements SynchronousConfigurationListener {
                deployConfigs.put(serviceDn, attrs);
        }
 
-       void saveDeployedConfigs() throws IOException {
+       void save() {
                try (Writer writer = Files.newBufferedWriter(deployConfigPath)) {
                        new LdifWriter(writer).write(deployConfigs);
+               } catch (IOException e) {
+                       throw new CmsException("Cannot save deploy configs", e);
                }
        }
 
@@ -222,7 +224,7 @@ class DeployConfig implements SynchronousConfigurationListener {
                }
        }
 
-       private Dictionary<String, Object> getProps(String factoryPid, String cn) {
+       Dictionary<String, Object> getProps(String factoryPid, String cn) {
                Attributes attrs = deployConfigs.get(serviceDn(factoryPid, cn));
                if (attrs != null)
                        return new AttributesDictionary(attrs);
index 79e735976fbebe96bb50d8d4ab4a803ff9a0205d..2d9d31d21d8cc4d483dbc4ab3d46d5769889d3fc 100644 (file)
@@ -3,41 +3,39 @@ package org.argeo.cms.internal.kernel;
 import org.argeo.node.NodeConstants;
 
 public interface KernelConstants {
-       
-
-       //final static String TRANSACTIONS_HOME = "argeo.node.transactions.home";
-
-       final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" };
+       String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" };
 
        // Directories
-       final static String DIR_NODE = "node";
-       final static String DIR_REPOS = "repos";
-//     final static String DIR_DEPLOY = "deploy";
-       final static String DIR_TRANSACTIONS = "transactions";
-       final static String DIR_PKI = "pki";
-       final static String DIR_PKI_PRIVATE = DIR_PKI + "/private";
+       String DIR_NODE = "node";
+       String DIR_REPOS = "repos";
+       String DIR_TRANSACTIONS = "transactions";
+       String DIR_PKI = "pki";
+       String DIR_PKI_PRIVATE = DIR_PKI + "/private";
 
        // Files
        String DEPLOY_CONFIG_PATH = KernelConstants.DIR_NODE + '/' + NodeConstants.DEPLOY_BASEDN + ".ldif";
-       
+
        // Security
-       final static String DEFAULT_SECURITY_KEY = "argeo";
-       final static String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg";
-       final static String LOGIN_CONTEXT_KERNEL = "KERNEL";
-       final static String LOGIN_CONTEXT_HARDENED_KERNEL = "HARDENED_KERNEL";
+       String DEFAULT_SECURITY_KEY = "argeo";
+       String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg";
+       String LOGIN_CONTEXT_KERNEL = "KERNEL";
+       String LOGIN_CONTEXT_HARDENED_KERNEL = "HARDENED_KERNEL";
 
        // DAV
-       final static String WEBDAV_CONFIG = "/org/argeo/cms/internal/kernel/webdav-config.xml";
-       final static String PATH_DATA = "/data";
-       final static String WEBDAV_PUBLIC = PATH_DATA + "/public";
-       final static String WEBDAV_PRIVATE = PATH_DATA + "/files";
-       final static String REMOTING_PUBLIC = PATH_DATA + "/pub";
-       final static String REMOTING_PRIVATE = PATH_DATA + "/jcr";
+       String WEBDAV_CONFIG = "/org/argeo/cms/internal/kernel/webdav-config.xml";
+       String PATH_DATA = "/data";
+       String WEBDAV_PUBLIC = PATH_DATA + "/public";
+       String WEBDAV_PRIVATE = PATH_DATA + "/files";
+       String REMOTING_PUBLIC = PATH_DATA + "/pub";
+       String REMOTING_PRIVATE = PATH_DATA + "/jcr";
 
        // RWT / RAP
-       final static String PATH_WORKBENCH = "/ui";
-       final static String PATH_WORKBENCH_PUBLIC = PATH_WORKBENCH + "/public";
+       String PATH_WORKBENCH = "/ui";
+       String PATH_WORKBENCH_PUBLIC = PATH_WORKBENCH + "/public";
 
-       final static String JETTY_FACTORY_PID = "org.eclipse.equinox.http.jetty.config"; //$NON-NLS-1$
+       String JETTY_FACTORY_PID = "org.eclipse.equinox.http.jetty.config";
+       String WHITEBOARD_PATTERN_PROP = "osgi.http.whiteboard.servlet.pattern";
 
+       // avoid dependency to RWT OSGi
+       String CONTEXT_NAME_PROP = "contextName";
 }
index b9475446e5c50a3a04f25030f73ee84e8c9f0bc6..3de2c7934ac43f221aca27d1cdc5ed8ddf44f281 100644 (file)
@@ -41,6 +41,10 @@ import org.argeo.ArgeoException;
 import org.argeo.cms.auth.CurrentUser;
 import org.argeo.node.ArgeoLogListener;
 import org.argeo.node.ArgeoLogger;
+import org.argeo.node.NodeConstants;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.log.LogEntry;
 import org.osgi.service.log.LogListener;
 import org.osgi.service.log.LogReaderService;
@@ -135,15 +139,56 @@ class NodeLogger implements ArgeoLogger, LogListener {
                        // FIXME Fix Argeo TP
                        if (status.getException() instanceof SignatureException)
                                return;
-                       pluginLog.error(status.getMessage(), status.getException());
+                       pluginLog.error(msg(status), status.getException());
                } else if (severity == LogService.LOG_WARNING)
-                       pluginLog.warn(status.getMessage(), status.getException());
+                       pluginLog.warn(msg(status), status.getException());
                else if (severity == LogService.LOG_INFO && pluginLog.isDebugEnabled())
-                       pluginLog.debug(
-                                       status.getMessage() + (status.getServiceReference() != null ?" "+ status.getServiceReference() : ""),
-                                       status.getException());
+                       pluginLog.debug(msg(status), status.getException());
                else if (severity == LogService.LOG_DEBUG && pluginLog.isTraceEnabled())
-                       pluginLog.trace(status.getMessage(), status.getException());
+                       pluginLog.trace(msg(status), status.getException());
+       }
+
+       private String msg(LogEntry status) {
+               StringBuilder sb = new StringBuilder(status.getMessage());
+               ServiceReference<?> sr = status.getServiceReference();
+               if (sr != null) {
+                       sb.append(' ');
+                       String[] objectClasses = (String[]) sr.getProperty(Constants.OBJECTCLASS);
+                       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);
+                       }
+                       // servlets
+                       Object whiteBoardPattern = sr.getProperty(KernelConstants.WHITEBOARD_PATTERN_PROP);
+                       if (whiteBoardPattern != null)
+                               sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": "
+                                               + arrayToString((String[]) whiteBoardPattern));
+                       // RWT
+                       Object contextName = sr.getProperty(KernelConstants.CONTEXT_NAME_PROP);
+                       if (contextName != null)
+                               sb.append(" " + KernelConstants.CONTEXT_NAME_PROP + ": " + contextName);
+               }
+               return sb.toString();
+       }
+
+       private String arrayToString(Object[] arr) {
+               StringBuilder sb = new StringBuilder();
+               sb.append('{');
+               for (int i = 0; i < arr.length; i++) {
+                       if (i != 0)
+                               sb.append(',');
+                       sb.append(arr[i]);
+               }
+               sb.append('}');
+               return sb.toString();
        }
 
        //