From 828c592e047d6dd0b88c1835093e07b1526036b0 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 6 Sep 2016 08:19:14 +0000 Subject: [PATCH] Stabilise deployment git-svn-id: https://svn.argeo.org/commons/trunk@9090 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- demo/log4j.properties | 3 - .../src/org/argeo/node/NodeDeployment.java | 2 +- .../src/org/argeo/node/NodeState.java | 3 + .../argeo/cms/internal/kernel/Activator.java | 123 ++++------ .../cms/internal/kernel/CmsDeployment.java | 158 +++++++++---- .../cms/internal/kernel/CmsInstance.java | 43 ++++ .../argeo/cms/internal/kernel/CmsState.java | 216 ++---------------- .../cms/internal/kernel/DeployConfig.java | 20 +- .../cms/internal/kernel/KernelConstants.java | 48 ++-- .../argeo/cms/internal/kernel/NodeLogger.java | 57 ++++- 10 files changed, 321 insertions(+), 352 deletions(-) create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java diff --git a/demo/log4j.properties b/demo/log4j.properties index 94c48c3d7..a3854b0c1 100644 --- a/demo/log4j.properties +++ b/demo/log4j.properties @@ -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 diff --git a/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java b/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java index 1b04d6809..8e5558d60 100644 --- a/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java +++ b/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java @@ -1,5 +1,5 @@ package org.argeo.node; public interface NodeDeployment { - long getAvailableSince(); + Long getAvailableSince(); } diff --git a/org.argeo.cms.api/src/org/argeo/node/NodeState.java b/org.argeo.cms.api/src/org/argeo/node/NodeState.java index 7568cd95b..d7148c68f 100644 --- a/org.argeo.cms.api/src/org/argeo/node/NodeState.java +++ b/org.argeo.cms.api/src/org/argeo/node/NodeState.java @@ -11,4 +11,7 @@ public interface NodeState { String getHostname(); boolean isClean(); + + Long getAvailableSince(); + } 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 6aacfd493..ecd36476f 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 @@ -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 props = nodeConf.getProperties(); - if (props == null) { - if (log.isDebugEnabled()) - log.debug("Clean node state"); - Dictionary 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 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 props = nodeConf.getProperties(); + // if (props == null) { + // if (log.isDebugEnabled()) + // log.debug("Clean node state"); + // Dictionary 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 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 getService(Class clazz) { 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 724108fb1..45e218a15 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 @@ -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 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(bc, UserAdmin.class, null) { + @Override + public UserAdmin addingService(ServiceReference 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 regProps = new Hashtable(); regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_HOME); @@ -140,22 +176,22 @@ public class CmsDeployment implements NodeDeployment { Hashtable 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 { + private class RepositoryContextStc extends ServiceTracker { + + public RepositoryContextStc() { + super(bc, RepositoryContext.class, null); + } @Override public RepositoryContext addingService(ServiceReference 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 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 { + private DataHttp dataHttp; + private NodeHttp nodeHttp; + + public PrepareHttpStc() { + super(bc, HttpService.class, null); + } + + @Override + public HttpService addingService(ServiceReference reference) { + HttpService httpService = addHttpService(reference); + return httpService; + } + + @Override + public void removedService(ServiceReference reference, HttpService service) { + if (dataHttp != null) + dataHttp.destroy(); + dataHttp = null; + if (nodeHttp != null) + nodeHttp.destroy(); + nodeHttp = null; + } + + private HttpService addHttpService(ServiceReference 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 index 000000000..795f063fb --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java @@ -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(bc, Repository.class, null) { + @Override + public Repository addingService(ServiceReference 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() { + + } + +} 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 f8073c46f..23d2f266d 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 @@ -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 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 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 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(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 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 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 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 { - private DataHttp dataHttp; - private NodeHttp nodeHttp; - - @Override - public HttpService addingService(ServiceReference reference) { - HttpService httpService = addHttpService(reference); - return httpService; - } - - @Override - public void modifiedService(ServiceReference reference, HttpService service) { - } - - @Override - public void removedService(ServiceReference reference, HttpService service) { - if (dataHttp != null) - dataHttp.destroy(); - dataHttp = null; - if (nodeHttp != null) - nodeHttp.destroy(); - nodeHttp = null; - } - - private HttpService addHttpService(ServiceReference 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 { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java index 376323aac..572631eff 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java @@ -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 getProps(String factoryPid, String cn) { + Dictionary getProps(String factoryPid, String cn) { Attributes attrs = deployConfigs.get(serviceDn(factoryPid, cn)); if (attrs != null) return new AttributesDictionary(attrs); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java index 79e735976..2d9d31d21 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java @@ -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"; } 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 b9475446e..3de2c7934 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 @@ -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(); } // -- 2.30.2