Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2018-05-20 07:39:45 +0000
committerEike Stepper2018-05-20 07:39:45 +0000
commit58168ee30078b21e11cb1e11267c2b1dfa3787c1 (patch)
tree0784dbfaea772242bfc0126214c3c690491d2faa
parent510ff43670eab4a25a23e99dc503476c5a398b81 (diff)
downloadcdo-58168ee30078b21e11cb1e11267c2b1dfa3787c1.tar.gz
cdo-58168ee30078b21e11cb1e11267c2b1dfa3787c1.tar.xz
cdo-58168ee30078b21e11cb1e11267c2b1dfa3787c1.zip
[534898] Provide a repository activity logbuffer-trace
https://bugs.eclipse.org/bugs/show_bug.cgi?id=534898
-rw-r--r--plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml7
-rw-r--r--plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml7
-rw-r--r--plugins/org.eclipse.emf.cdo.server.admin/src/org/eclipse/emf/cdo/server/internal/admin/RepositoryConfigurationManagerExtension.java1
-rw-r--r--plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml7
-rw-r--r--plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.server/plugin.xml8
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java14
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryActivityLog.java293
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java101
-rw-r--r--plugins/org.eclipse.net4j.util/plugin.xml3
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/ConcurrencyUtil.java8
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RunnableWithName.java4
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/factory/PropertiesFactory.java93
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/lifecycle/LifecycleHook.java167
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/Log.java20
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/RollingLog.java328
16 files changed, 1060 insertions, 6 deletions
diff --git a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
index 1936e4bc5e..e00f297083 100644
--- a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
@@ -42,6 +42,13 @@
<initialPackage nsURI="http://www.eclipse.org/emf/CDO/examples/company/1.0.0"/>
-->
+ <!-- Example http://bugs.eclipse.org/534898
+ <activityLog type="rolling">
+ <property name="file" value="/develop/cdo-master/repo1-activities"/>
+ <property name="size" value="100000000"/>
+ </activityLog>
+ -->
+
<store type="db">
<!-- Example http://bugs.eclipse.org/396379 (if idGenerationLocation == CLIENT)
diff --git a/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
index 1936e4bc5e..e00f297083 100644
--- a/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
@@ -42,6 +42,13 @@
<initialPackage nsURI="http://www.eclipse.org/emf/CDO/examples/company/1.0.0"/>
-->
+ <!-- Example http://bugs.eclipse.org/534898
+ <activityLog type="rolling">
+ <property name="file" value="/develop/cdo-master/repo1-activities"/>
+ <property name="size" value="100000000"/>
+ </activityLog>
+ -->
+
<store type="db">
<!-- Example http://bugs.eclipse.org/396379 (if idGenerationLocation == CLIENT)
diff --git a/plugins/org.eclipse.emf.cdo.server.admin/src/org/eclipse/emf/cdo/server/internal/admin/RepositoryConfigurationManagerExtension.java b/plugins/org.eclipse.emf.cdo.server.admin/src/org/eclipse/emf/cdo/server/internal/admin/RepositoryConfigurationManagerExtension.java
index ac9536b211..daccf819fb 100644
--- a/plugins/org.eclipse.emf.cdo.server.admin/src/org/eclipse/emf/cdo/server/internal/admin/RepositoryConfigurationManagerExtension.java
+++ b/plugins/org.eclipse.emf.cdo.server.admin/src/org/eclipse/emf/cdo/server/internal/admin/RepositoryConfigurationManagerExtension.java
@@ -128,6 +128,7 @@ public class RepositoryConfigurationManagerExtension implements IAppExtension
.getElement(CDORepositoryConfigurationManager.Factory.PRODUCT_GROUP, type, description);
repoManager.setAdminRepository(repository);
+ OM.LOG.info("Admin repository: " + repository.getName());
return repoManager;
}
diff --git a/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
index 9ae1abb2d7..9b8209e539 100644
--- a/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
@@ -42,6 +42,13 @@
<initialPackage nsURI="http://www.eclipse.org/emf/CDO/examples/company/1.0.0"/>
-->
+ <!-- Example http://bugs.eclipse.org/534898
+ <activityLog type="rolling">
+ <property name="file" value="/develop/cdo-master/repo1-activities"/>
+ <property name="size" value="100000000"/>
+ </activityLog>
+ -->
+
<store type="db">
<!-- Example http://bugs.eclipse.org/396379 (if idGenerationLocation == CLIENT)
diff --git a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java
index 49c23fe642..6618dfe40f 100644
--- a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java
+++ b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java
@@ -128,7 +128,10 @@ public class SecurityExtension implements IAppExtension2
}
String qualifiedDescription = String.format("%s:%s", name, description); //$NON-NLS-1$
- container.getElement(SecurityManagerFactory.PRODUCT_GROUP, type, qualifiedDescription);
+ if (container.getElement(SecurityManagerFactory.PRODUCT_GROUP, type, qualifiedDescription) != null)
+ {
+ OM.LOG.info("Security manager for repository " + repository.getName() + ": " + qualifiedDescription);
+ }
}
}
diff --git a/plugins/org.eclipse.emf.cdo.server/plugin.xml b/plugins/org.eclipse.emf.cdo.server/plugin.xml
index f0c3af0960..f67d040a67 100644
--- a/plugins/org.eclipse.emf.cdo.server/plugin.xml
+++ b/plugins/org.eclipse.emf.cdo.server/plugin.xml
@@ -19,6 +19,14 @@
<extension point="org.eclipse.net4j.util.factories">
<factory
+ productGroup="org.eclipse.emf.cdo.server.repositoryConfigurators"
+ type="default"
+ class="org.eclipse.emf.cdo.spi.server.RepositoryConfigurator$Factory$Default"/>
+ <factory
+ productGroup="org.eclipse.emf.cdo.server.repositoryActivityLogs"
+ type="rolling"
+ class="org.eclipse.emf.cdo.spi.server.RepositoryActivityLog$Rolling$Factory"/>
+ <factory
productGroup="org.eclipse.net4j.Negotiators"
type="challenge"
class="org.eclipse.net4j.util.security.ChallengeNegotiatorFactory"/>
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java
index 1ffaf5358b..1a4b660bdc 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java
@@ -36,6 +36,10 @@ public class CDOServerApplication extends OSGiApplication
{
public static final String ID = OM.BUNDLE_ID + ".app"; //$NON-NLS-1$
+ public static final String PROP_CONFIGURATOR_TYPE = "org.eclipse.emf.cdo.server.repositoryConfiguratorType";
+
+ public static final String PROP_CONFIGURATOR_DESCRIPTION = "org.eclipse.emf.cdo.server.repositoryConfiguratorDescription";
+
public static final String PROP_BROWSER_PORT = "org.eclipse.emf.cdo.server.browser.port"; //$NON-NLS-1$
private IRepository[] repositories;
@@ -47,6 +51,13 @@ public class CDOServerApplication extends OSGiApplication
super(ID);
}
+ protected RepositoryConfigurator getConfigurator(IManagedContainer container)
+ {
+ String type = OMPlatform.INSTANCE.getProperty(PROP_CONFIGURATOR_TYPE, RepositoryConfigurator.Factory.Default.TYPE);
+ String description = OMPlatform.INSTANCE.getProperty(PROP_CONFIGURATOR_DESCRIPTION);
+ return (RepositoryConfigurator)container.getElement(RepositoryConfigurator.Factory.PRODUCT_GROUP, type, description);
+ }
+
@Override
protected void doStart() throws Exception
{
@@ -57,7 +68,8 @@ public class CDOServerApplication extends OSGiApplication
File configFile = OMPlatform.INSTANCE.getConfigFile("cdo-server.xml"); //$NON-NLS-1$
if (configFile != null && configFile.exists())
{
- RepositoryConfigurator repositoryConfigurator = new RepositoryConfigurator(container);
+ RepositoryConfigurator repositoryConfigurator = getConfigurator(container);
+
repositories = repositoryConfigurator.configure(configFile);
if (repositories == null || repositories.length == 0)
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryActivityLog.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryActivityLog.java
new file mode 100644
index 0000000000..16fe141762
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryActivityLog.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2004-2018 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.spi.server;
+
+import org.eclipse.emf.cdo.internal.server.bundle.OM;
+import org.eclipse.emf.cdo.server.IRepository;
+import org.eclipse.emf.cdo.server.IRepository.WriteAccessHandler;
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.IView;
+
+import org.eclipse.net4j.util.StringUtil;
+import org.eclipse.net4j.util.container.ContainerEventAdapter;
+import org.eclipse.net4j.util.container.IContainer;
+import org.eclipse.net4j.util.event.IListener;
+import org.eclipse.net4j.util.factory.ProductCreationException;
+import org.eclipse.net4j.util.lifecycle.LifecycleHook;
+import org.eclipse.net4j.util.om.log.Log;
+import org.eclipse.net4j.util.om.log.RollingLog;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author Eike Stepper
+ * @since 4.7
+ */
+public abstract class RepositoryActivityLog extends LifecycleHook<IRepository> implements Log
+{
+ private final IListener sessionManagerListener = new ContainerEventAdapter<ISession>()
+ {
+ @Override
+ protected void onAdded(IContainer<ISession> container, ISession session)
+ {
+ sessionOpened(session, concurrentSessions.incrementAndGet(), sessions.incrementAndGet());
+ session.addListener(sessionListener);
+ }
+
+ @Override
+ protected void onRemoved(IContainer<ISession> container, ISession session)
+ {
+ session.removeListener(sessionListener);
+ sessionClosed(session, concurrentSessions.decrementAndGet());
+ }
+ };
+
+ private final IListener sessionListener = new ContainerEventAdapter<IView>()
+ {
+ @Override
+ protected void onAdded(IContainer<IView> container, IView view)
+ {
+ if (view instanceof ITransaction)
+ {
+ transactionOpened((ITransaction)view, concurrentTransactions.incrementAndGet(), transactions.incrementAndGet());
+ }
+ else
+ {
+ viewOpened(view, concurrentViews.incrementAndGet(), views.incrementAndGet());
+ }
+ }
+
+ @Override
+ protected void onRemoved(IContainer<IView> container, IView view)
+ {
+ if (view instanceof ITransaction)
+ {
+ transactionClosed((ITransaction)view, concurrentTransactions.decrementAndGet());
+ }
+ else
+ {
+ viewClosed(view, concurrentViews.decrementAndGet());
+ }
+ }
+ };
+
+ private final WriteAccessHandler writeAccessHandler = new WriteAccessHandler()
+ {
+ public void handleTransactionBeforeCommitting(ITransaction transaction, CommitContext commitContext, OMMonitor monitor) throws RuntimeException
+ {
+ commitStarted(commitContext, concurrentCommits.incrementAndGet(), commits.incrementAndGet());
+ }
+
+ public void handleTransactionAfterCommitted(ITransaction transaction, CommitContext commitContext, OMMonitor monitor)
+ {
+ commitFinished(commitContext, concurrentCommits.decrementAndGet());
+ }
+ };
+
+ private final AtomicInteger sessions = new AtomicInteger();
+
+ private final AtomicInteger views = new AtomicInteger();
+
+ private final AtomicInteger transactions = new AtomicInteger();
+
+ private final AtomicInteger commits = new AtomicInteger();
+
+ private final AtomicInteger concurrentSessions = new AtomicInteger();
+
+ private final AtomicInteger concurrentViews = new AtomicInteger();
+
+ private final AtomicInteger concurrentTransactions = new AtomicInteger();
+
+ private final AtomicInteger concurrentCommits = new AtomicInteger();
+
+ public RepositoryActivityLog()
+ {
+ }
+
+ public IRepository getRepository()
+ {
+ return getDelegate();
+ }
+
+ public void setRepository(IRepository repository)
+ {
+ setDelegate(repository);
+ }
+
+ protected void sessionOpened(ISession session, int concurrentSessions, int sessions)
+ {
+ log(formatSession(session) + " opened" + formatUser(session) + " (" + concurrentSessions + "/" + sessions + ")");
+ }
+
+ protected void sessionClosed(ISession session, int concurrentSessions)
+ {
+ log(formatSession(session) + " closed" + formatUser(session) + " (" + concurrentSessions + ")");
+ }
+
+ protected void viewOpened(IView view, int concurrentViews, int views)
+ {
+ log(formatView(view) + " opened" + formatUser(view.getSession()) + " (" + concurrentViews + "/" + views + ")");
+ }
+
+ protected void viewClosed(IView view, int concurrentViews)
+ {
+ log(formatView(view) + " closed" + formatUser(view.getSession()) + " (" + concurrentViews + ")");
+ }
+
+ protected void transactionOpened(ITransaction transaction, int concurrentTransactions, int transactions)
+ {
+ log(formatView(transaction) + " opened" + formatUser(transaction.getSession()) + " (" + concurrentTransactions + "/" + transactions + ")");
+ }
+
+ protected void transactionClosed(ITransaction transaction, int concurrentTransactions)
+ {
+ log(formatView(transaction) + " closed" + formatUser(transaction.getSession()) + " (" + concurrentTransactions + ")");
+ }
+
+ protected void commitStarted(CommitContext commitContext, int concurrentCommits, int commits)
+ {
+ ITransaction transaction = commitContext.getTransaction();
+ log(formatView(transaction) + " committing " + commitContext.getBranchPoint().getTimeStamp() + formatUser(transaction.getSession()) + " ("
+ + concurrentCommits + "/" + commits + ")");
+ }
+
+ protected void commitFinished(CommitContext commitContext, int concurrentCommits)
+ {
+ ITransaction transaction = commitContext.getTransaction();
+ log(formatView(transaction) + (commitContext.getRollbackMessage() != null ? " committed " : " rolled back ") + commitContext.getBranchPoint().getTimeStamp()
+ + formatUser(transaction.getSession()) + " (" + concurrentCommits + ")");
+ }
+
+ protected String formatSession(ISession session)
+ {
+ return "Session " + session.getSessionID();
+ }
+
+ protected String formatUser(ISession session)
+ {
+ String userID = session.getUserID();
+ return StringUtil.isEmpty(userID) ? "" : " by user " + userID;
+ }
+
+ protected String formatView(IView view)
+ {
+ return (view instanceof ITransaction ? "Transaction " : "View ") + view.getSessionID() + ":" + view.getViewID();
+ }
+
+ @Override
+ protected void hookDelegate(IRepository repository)
+ {
+ repository.getSessionManager().addListener(sessionManagerListener);
+ repository.addHandler(writeAccessHandler);
+ }
+
+ @Override
+ protected void unhookDelegate(IRepository repository)
+ {
+ repository.removeHandler(writeAccessHandler);
+ repository.getSessionManager().removeListener(sessionManagerListener);
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 4.7
+ */
+ public static abstract class Factory extends org.eclipse.net4j.util.factory.PropertiesFactory
+ {
+ public static final String PRODUCT_GROUP = "org.eclipse.emf.cdo.server.repositoryActivityLogs"; //$NON-NLS-1$
+
+ public Factory(String type)
+ {
+ super(PRODUCT_GROUP, type);
+ }
+
+ @Override
+ protected abstract RepositoryActivityLog create(Map<String, String> properties) throws ProductCreationException;
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 4.7
+ */
+ public static class Rolling extends RepositoryActivityLog
+ {
+ private final RollingLog rollingLog;
+
+ public Rolling(String logFile, long logSize)
+ {
+ rollingLog = new RollingLog(logFile, logSize);
+ }
+
+ public void log(String line)
+ {
+ rollingLog.log(line);
+ }
+
+ @Override
+ protected void delegateChanged(IRepository oldRepository, IRepository newRepository)
+ {
+ if (newRepository != null)
+ {
+ OM.LOG.info("Logging activities of repository " + newRepository.getName() + " to " + rollingLog.getLogFile());
+ }
+
+ }
+
+ @Override
+ protected void doActivate() throws Exception
+ {
+ rollingLog.activate();
+ super.doActivate();
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ super.doDeactivate();
+ rollingLog.deactivate();
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class Factory extends RepositoryActivityLog.Factory
+ {
+ public static final String TYPE = "rolling"; //$NON-NLS-1$
+
+ public Factory()
+ {
+ super(TYPE);
+ }
+
+ @Override
+ protected RepositoryActivityLog create(Map<String, String> properties) throws ProductCreationException
+ {
+ String file = properties.get("file"); //$NON-NLS-1$
+ if (file == null)
+ {
+ file = "activities";
+ }
+
+ String size = properties.get("size"); //$NON-NLS-1$
+ if (StringUtil.isEmpty(size))
+ {
+ size = "100000000";
+ }
+
+ return new RepositoryActivityLog.Rolling(file, Long.parseLong(size));
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java
index b9f206a472..07450bc700 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java
@@ -23,6 +23,9 @@ import org.eclipse.emf.cdo.server.IStoreFactory;
import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.container.IManagedContainer;
+import org.eclipse.net4j.util.container.IManagedContainer.ContainerAware;
+import org.eclipse.net4j.util.factory.ProductCreationException;
+import org.eclipse.net4j.util.factory.PropertiesFactory;
import org.eclipse.net4j.util.om.OMPlatform;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.net4j.util.security.AuthenticatorFactory;
@@ -136,6 +139,11 @@ public class RepositoryConfigurator
if (container != null)
{
CDOServerUtil.addRepository(container, repository);
+ OM.LOG.info("CDO repository " + repository.getName() + " started");
+ }
+ else
+ {
+ OM.LOG.info("CDO repository " + repository.getName() + " added");
}
}
@@ -207,6 +215,7 @@ public class RepositoryConfigurator
setUserManager(repository, repositoryConfig);
setAuthenticator(repository, repositoryConfig);
+ setActivityLog(repository, repositoryConfig);
EPackage[] initialPackages = getInitialPackages(repositoryConfig);
if (initialPackages.length != 0)
@@ -339,6 +348,27 @@ public class RepositoryConfigurator
}
}
+ /**
+ * @since 4.7
+ */
+ protected void setActivityLog(InternalRepository repository, Element repositoryConfig)
+ {
+ NodeList activityLogConfig = repositoryConfig.getElementsByTagName("activityLog"); //$NON-NLS-1$
+ if (activityLogConfig.getLength() > 1)
+ {
+ String repositoryName = repositoryConfig.getAttribute("name"); //$NON-NLS-1$
+ throw new IllegalStateException("At most one activity log must be configured for repository " + repositoryName); //$NON-NLS-1$
+ }
+
+ if (activityLogConfig.getLength() > 0)
+ {
+ Element activityLogElement = (Element)activityLogConfig.item(0);
+
+ RepositoryActivityLog activityLog = getContainerElement(activityLogElement, RepositoryActivityLog.Rolling.Factory.TYPE);
+ activityLog.setRepository(repository);
+ }
+ }
+
protected EPackage[] getInitialPackages(Element repositoryConfig)
{
List<EPackage> result = new ArrayList<EPackage>();
@@ -400,6 +430,30 @@ public class RepositoryConfigurator
return storeFactory.createStore(repositoryName, repositoryProperties, storeConfig);
}
+ /**
+ * @since 4.7
+ */
+ protected <T> T getContainerElement(Element element, String defaultType)
+ {
+ String type = element.getAttribute("type"); //$NON-NLS-1$
+ if (StringUtil.isEmpty(type))
+ {
+ type = defaultType;
+ }
+
+ String description = element.getAttribute("description"); //$NON-NLS-1$
+ if (StringUtil.isEmpty(description))
+ {
+ Map<String, String> properties = getProperties(element, 1);
+ description = PropertiesFactory.createDescription(properties);
+ }
+
+ @SuppressWarnings("unchecked")
+ T containerElement = (T)container.getElement(RepositoryActivityLog.Factory.PRODUCT_GROUP, type, description);
+
+ return containerElement;
+ }
+
public static Map<String, String> getProperties(Element element, int levels)
{
Map<String, String> properties = new HashMap<String, String>();
@@ -454,4 +508,51 @@ public class RepositoryConfigurator
return null;
}
+
+ /**
+ * @author Eike Stepper
+ * @since 4.7
+ */
+ public static abstract class Factory extends org.eclipse.net4j.util.factory.Factory implements ContainerAware
+ {
+ public static final String PRODUCT_GROUP = "org.eclipse.emf.cdo.server.repositoryConfigurators"; //$NON-NLS-1$
+
+ private IManagedContainer container;
+
+ public Factory(String type)
+ {
+ super(PRODUCT_GROUP, type);
+ }
+
+ public void setManagedContainer(IManagedContainer container)
+ {
+ this.container = container;
+ }
+
+ public final RepositoryConfigurator create(String description) throws ProductCreationException
+ {
+ return create(container, description);
+ }
+
+ public abstract RepositoryConfigurator create(IManagedContainer container, String description) throws ProductCreationException;
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class Default extends Factory
+ {
+ public static final String TYPE = "default"; //$NON-NLS-1$
+
+ public Default()
+ {
+ super(TYPE);
+ }
+
+ @Override
+ public RepositoryConfigurator create(IManagedContainer container, String description) throws ProductCreationException
+ {
+ return new RepositoryConfigurator(container);
+ }
+ }
+ }
}
diff --git a/plugins/org.eclipse.net4j.util/plugin.xml b/plugins/org.eclipse.net4j.util/plugin.xml
index 73d6d7c1c0..31b1dcc34e 100644
--- a/plugins/org.eclipse.net4j.util/plugin.xml
+++ b/plugins/org.eclipse.net4j.util/plugin.xml
@@ -42,8 +42,7 @@
<factory
productGroup="org.eclipse.net4j.util.confirmationProviders"
type="default"
- class="org.eclipse.net4j.util.confirmation.IConfirmationProvider.Factory.Default">
- </factory>
+ class="org.eclipse.net4j.util.confirmation.IConfirmationProvider.Factory.Default"/>
</extension>
</plugin>
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/ConcurrencyUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/ConcurrencyUtil.java
index 0ec46b678b..7d6ef1f175 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/ConcurrencyUtil.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/ConcurrencyUtil.java
@@ -115,4 +115,12 @@ public final class ConcurrencyUtil
thread.setDaemon(true);
thread.start();
}
+
+ /**
+ * @since 3.8
+ */
+ public static void setThreadName(Thread thread, String name)
+ {
+ thread.setName(name);
+ }
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RunnableWithName.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RunnableWithName.java
index 54feb65a7d..4bedf23ddd 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RunnableWithName.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RunnableWithName.java
@@ -44,7 +44,7 @@ public abstract class RunnableWithName implements Runnable
}
else
{
- thread.setName(name);
+ ConcurrencyUtil.setThreadName(thread, name);
}
}
@@ -56,7 +56,7 @@ public abstract class RunnableWithName implements Runnable
{
if (thread != null)
{
- thread.setName(oldName);
+ ConcurrencyUtil.setThreadName(thread, oldName);
}
}
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/factory/PropertiesFactory.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/factory/PropertiesFactory.java
new file mode 100644
index 0000000000..f8e18ec6f9
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/factory/PropertiesFactory.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.factory;
+
+import org.eclipse.net4j.util.StringUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Eike Stepper
+ * @since 3.8
+ */
+public abstract class PropertiesFactory extends Factory
+{
+ public static final String PROPERTY_SEPARATOR = "|";
+
+ public static final String DEFAULT_KEY = "_";
+
+ public PropertiesFactory(FactoryKey key)
+ {
+ super(key);
+ }
+
+ public PropertiesFactory(String productGroup, String type)
+ {
+ super(productGroup, type);
+ }
+
+ public Object create(String description) throws ProductCreationException
+ {
+ Map<String, String> properties = new HashMap<String, String>();
+
+ if (!StringUtil.isEmpty(description))
+ {
+ String[] segments = description.split("\\" + PROPERTY_SEPARATOR);
+ for (String segment : segments)
+ {
+ if (!StringUtil.isEmpty(segment))
+ {
+ int pos = segment.indexOf('=');
+ if (pos != -1)
+ {
+ String key = segment.substring(0, pos).trim();
+ String value = segment.substring(pos + 1).trim();
+ properties.put(key, value);
+ }
+ else
+ {
+ properties.put(DEFAULT_KEY, segment);
+ }
+ }
+ }
+ }
+
+ return create(properties);
+ }
+
+ protected abstract Object create(Map<String, String> properties) throws ProductCreationException;
+
+ public static String createDescription(Map<String, String> properties)
+ {
+ StringBuilder builder = new StringBuilder();
+
+ String defaultValue = properties.remove(DEFAULT_KEY);
+ if (!StringUtil.isEmpty(defaultValue))
+ {
+ builder.append(defaultValue);
+ }
+
+ for (Map.Entry<String, String> entry : properties.entrySet())
+ {
+ if (builder.length() != 0)
+ {
+ builder.append(PROPERTY_SEPARATOR);
+ }
+
+ builder.append(entry.getKey());
+ builder.append("=");
+ builder.append(entry.getValue());
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/lifecycle/LifecycleHook.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/lifecycle/LifecycleHook.java
new file mode 100644
index 0000000000..07a57b3d1f
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/lifecycle/LifecycleHook.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2018 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.lifecycle;
+
+import org.eclipse.net4j.util.event.IEvent;
+import org.eclipse.net4j.util.event.IListener;
+
+/**
+ * @author Eike Stepper
+ * @since 3.8
+ */
+public class LifecycleHook<T extends ILifecycle> extends Lifecycle
+{
+ private final IListener delegateListener = new LifecycleEventAdapter()
+ {
+ @Override
+ protected void notifyOtherEvent(IEvent event)
+ {
+ delegateEvent(delegate, event);
+ }
+
+ @Override
+ protected void onAboutToActivate(ILifecycle lifecycle)
+ {
+ delegateAboutToActivate(delegate);
+ }
+
+ @Override
+ protected void onAboutToDeactivate(ILifecycle lifecycle)
+ {
+ delegateAboutToDeactivate(delegate);
+ }
+
+ @Override
+ protected void onActivated(ILifecycle lifecycle)
+ {
+ delegateActivated(delegate);
+ hookDelegateIfPossible();
+ }
+
+ @Override
+ protected void onDeactivated(ILifecycle lifecycle)
+ {
+ unhookDelegateIfPossible();
+ delegateDeactivated(delegate);
+ }
+ };
+
+ private T delegate;
+
+ private boolean listening;
+
+ private boolean delegateHooked;
+
+ public LifecycleHook()
+ {
+ }
+
+ protected final T getDelegate()
+ {
+ return delegate;
+ }
+
+ protected final void setDelegate(T delegate)
+ {
+ T oldDelegate = this.delegate;
+
+ if (oldDelegate != delegate)
+ {
+ unhookDelegateIfPossible();
+ this.delegate = delegate;
+ hookDelegateIfPossible();
+
+ delegateChanged(oldDelegate, delegate);
+ }
+ }
+
+ protected void delegateChanged(T oldDelegate, T newDelegate)
+ {
+ }
+
+ protected void delegateEvent(T delegate, IEvent event)
+ {
+ }
+
+ protected void delegateAboutToActivate(T delegate)
+ {
+ }
+
+ protected void delegateActivated(T delegate)
+ {
+ }
+
+ protected void delegateAboutToDeactivate(T delegate)
+ {
+ }
+
+ protected void delegateDeactivated(T delegate)
+ {
+ }
+
+ @Override
+ protected void doActivate() throws Exception
+ {
+ hookDelegateIfPossible();
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ unhookDelegateIfPossible();
+ }
+
+ protected void hookDelegate(T delegate)
+ {
+ }
+
+ protected void unhookDelegate(T delegate)
+ {
+ }
+
+ protected boolean hookInactiveDelegates()
+ {
+ return false;
+ }
+
+ private void hookDelegateIfPossible()
+ {
+ if (!listening && delegate != null)
+ {
+ delegate.addListener(delegateListener);
+ listening = true;
+ }
+
+ if (listening && !delegateHooked && (hookInactiveDelegates() || delegate.isActive()))
+ {
+ hookDelegate(delegate);
+ delegateHooked = true;
+ }
+ }
+
+ private void unhookDelegateIfPossible()
+ {
+ if (delegate != null)
+ {
+ if (delegateHooked)
+ {
+ unhookDelegate(delegate);
+ delegateHooked = false;
+ }
+
+ if (listening)
+ {
+ delegate.removeListener(delegateListener);
+ listening = false;
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/Log.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/Log.java
new file mode 100644
index 0000000000..ec858c7fe6
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/Log.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.om.log;
+
+/**
+ * @author Eike Stepper
+ * @since 3.8
+ */
+public interface Log
+{
+ public void log(String line);
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/RollingLog.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/RollingLog.java
new file mode 100644
index 0000000000..011f1e59c7
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/log/RollingLog.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2018 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.om.log;
+
+import org.eclipse.net4j.internal.util.bundle.OM;
+import org.eclipse.net4j.util.collection.AbstractIterator;
+import org.eclipse.net4j.util.collection.CloseableIterator;
+import org.eclipse.net4j.util.concurrent.Worker;
+import org.eclipse.net4j.util.io.IOUtil;
+import org.eclipse.net4j.util.om.log.RollingLog.LogLine;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * @author Eike Stepper
+ * @since 3.8
+ */
+public class RollingLog extends Worker implements Log, Iterable<LogLine>
+{
+ private final String logFile;
+
+ private final long logSize;
+
+ private final AtomicLong logLineCounter = new AtomicLong(0);
+
+ private int fileNumber;
+
+ private boolean fileAppend;
+
+ private List<LogLine> queue = new ArrayList<LogLine>();
+
+ public RollingLog(String logFile, long logSize)
+ {
+ this.logFile = logFile;
+ this.logSize = logSize;
+
+ setDaemon(true);
+ }
+
+ public final String getLogFile()
+ {
+ return logFile;
+ }
+
+ public final long getLogSize()
+ {
+ return logSize;
+ }
+
+ public final void log(String line)
+ {
+ LogLine logLine = createLogLine(line);
+
+ synchronized (this)
+ {
+ logLine.id = logLineCounter.incrementAndGet();
+ queue.add(logLine);
+ notifyAll();
+ }
+ }
+
+ @Override
+ protected final void work(WorkContext context) throws Exception
+ {
+ List<LogLine> logLines;
+ synchronized (this)
+ {
+ if (queue.isEmpty())
+ {
+ try
+ {
+ wait(100);
+ }
+ catch (InterruptedException ex)
+ {
+ context.terminate();
+ }
+
+ context.nextWork();
+ }
+
+ logLines = queue;
+ queue = new ArrayList<LogLine>();
+ }
+
+ writeLogLines(logLines);
+ }
+
+ protected LogLine createLogLine(String line)
+ {
+ long millis = System.currentTimeMillis();
+ String thread = getThreadInfo();
+
+ return new LogLine(millis, thread, line);
+ }
+
+ protected void writeLogLines(List<LogLine> logLines)
+ {
+ if (logFile != null)
+ {
+ PrintStream out = null;
+
+ try
+ {
+ File file;
+
+ for (;;)
+ {
+ file = getFile(logFile, fileNumber);
+
+ if (fileAppend && file.length() > logSize)
+ {
+ fileNumber++;
+ fileAppend = false;
+ continue;
+ }
+
+ break;
+ }
+
+ out = new PrintStream(new FileOutputStream(file, fileAppend));
+ writeLogLines(logLines, out);
+ out.close();
+ }
+ catch (IOException ex)
+ {
+ OM.LOG.error(ex);
+ }
+ finally
+ {
+ fileAppend = true;
+ IOUtil.closeSilent(out);
+ }
+ }
+ else
+ {
+ writeLogLines(logLines, System.out);
+ }
+ }
+
+ protected void writeLogLines(List<LogLine> logLines, PrintStream out)
+ {
+ for (LogLine logLine : logLines)
+ {
+ writeLogLine(logLine, out);
+ }
+ }
+
+ protected void writeLogLine(LogLine logLine, PrintStream out)
+ {
+ out.println(logLine);
+ }
+
+ protected String getThreadInfo()
+ {
+ return Thread.currentThread().getName();
+ }
+
+ public final CloseableIterator<LogLine> iterator()
+ {
+ return iterator(logFile);
+ }
+
+ public static CloseableIterator<LogLine> iterator(String logFile)
+ {
+ return new LogIterator(logFile);
+ }
+
+ private static File getFile(String logFile, int fileNumber)
+ {
+ return new File(logFile + String.format("-%04d", fileNumber) + ".txt");
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class LogIterator extends AbstractIterator<LogLine> implements CloseableIterator<LogLine>
+ {
+ private static final int CLOSED = -1;
+
+ private final String logFile;
+
+ private int fileNumber;
+
+ private BufferedReader reader;
+
+ public LogIterator(String logFile)
+ {
+ this.logFile = logFile;
+ }
+
+ @Override
+ protected Object computeNextElement()
+ {
+ if (fileNumber == CLOSED)
+ {
+ return END_OF_DATA;
+ }
+
+ if (reader == null)
+ {
+ File file = getFile(logFile, fileNumber++);
+ if (file.isFile())
+ {
+ try
+ {
+ reader = new BufferedReader(new FileReader(file));
+ }
+ catch (FileNotFoundException ex)
+ {
+ OM.LOG.error(ex);
+ return END_OF_DATA;
+ }
+ }
+ else
+ {
+ return END_OF_DATA;
+ }
+ }
+
+ try
+ {
+ String string = reader.readLine();
+ if (string == null)
+ {
+ reader.close();
+ reader = null;
+ return computeNextElement();
+ }
+
+ return new LogLine(string);
+ }
+ catch (IOException ex)
+ {
+ OM.LOG.error(ex);
+ return END_OF_DATA;
+ }
+ }
+
+ public void close()
+ {
+ IOUtil.close(reader);
+ reader = null;
+ fileNumber = CLOSED;
+ }
+
+ public boolean isClosed()
+ {
+ return fileNumber == CLOSED;
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class LogLine
+ {
+ private static final String TAB = "\t";
+
+ private long id;
+
+ private final long millis;
+
+ private final String thread;
+
+ private final String line;
+
+ public LogLine(long millis, String thread, String line)
+ {
+ this.millis = millis;
+ this.thread = thread;
+ this.line = line;
+ }
+
+ public LogLine(String string)
+ {
+ StringTokenizer tokenizer = new StringTokenizer(string, TAB);
+ id = Long.parseLong(tokenizer.nextToken());
+ millis = Long.parseLong(tokenizer.nextToken());
+ thread = tokenizer.nextToken();
+ line = tokenizer.nextToken("").substring(1);
+ }
+
+ public long getID()
+ {
+ return id;
+ }
+
+ public long getMillis()
+ {
+ return millis;
+ }
+
+ public String getThread()
+ {
+ return thread;
+ }
+
+ public String getLine()
+ {
+ return line;
+ }
+
+ @Override
+ public String toString()
+ {
+ return id + TAB + millis + TAB + thread + TAB + line;
+ }
+ }
+}

Back to the top