Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.virgo.kernel.services/src')
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceDelegate.java151
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceInfo.java78
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceStatistics.java76
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelExecutorService.java27
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledExecutorService.java27
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutor.java101
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutor.java111
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/NamedThreadFactory.java47
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/PersistentThreadLocal.java24
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ThreadPoolUtils.java31
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/diagnostics/ConcurrentLogEvents.java54
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/ExecutorServiceExporter.java28
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporter.java79
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/StandardExecutorServiceInfo.java106
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyser.java234
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockMonitor.java130
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/internal/KernelServicesLogEvents.java54
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepository.java93
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBean.java109
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/StandardWorkArea.java65
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkArea.java40
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactory.java46
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/resources/EventLogMessages.properties4
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/concurrent-context.xml33
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/configuration-context.xml16
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/io-context.xml20
-rw-r--r--org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/repository-context.xml62
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/AbstractExecutorTests.java78
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutorTests.java51
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutorTests.java128
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporterTests.java110
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyserTests.java60
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreator.java124
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreatorMBean.java19
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepositoryTests.java32
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBeanTests.java91
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/StandardWorkAreaTests.java55
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactoryTests.java41
-rw-r--r--org.eclipse.virgo.kernel.services/src/test/resources/.gitignore0
39 files changed, 2635 insertions, 0 deletions
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceDelegate.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceDelegate.java
new file mode 100644
index 00000000..451a02bd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceDelegate.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.eclipse.virgo.kernel.shim.serviceability.TracingService;
+
+
+/**
+ * Delegate object that encapsulates common operations for {@link ExecutorService} implementations.
+ * <p/>
+ * Each {@link ExecutorService} should maintain its own instance of <code>ExecutorServiceDelegate</code>.
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Threadsafe.
+ *
+ */
+final class ExecutorServiceDelegate {
+
+ private final ApplicationNameAccessor accessor;
+
+ private final Object monitor = new Object();
+
+ private long totalExecutionTime;
+
+ public ExecutorServiceDelegate(TracingService tracingService) {
+ this.accessor = new ApplicationNameAccessor(tracingService);
+ }
+
+ /**
+ * Gets an estimate of the average amount of time spent processing successful tasks.
+ * @param completedTaskCount
+ * @return the estimate of time spent.
+ * @see ThreadPoolExecutor#getCompletedTaskCount()
+ */
+ public long getAverageExecutionTime(long completedTaskCount) {
+ synchronized (this.monitor) {
+ return completedTaskCount == 0 ? this.totalExecutionTime : this.totalExecutionTime / completedTaskCount;
+ }
+ }
+
+ /**
+ * Gets an estimate of the total amount of time spent processing successful tasks.
+ *
+ * @return the estimate of time spent.
+ * @see ThreadPoolExecutor#getCompletedTaskCount()
+ */
+ public long getExecutionTime() {
+ synchronized (this.monitor) {
+ return this.totalExecutionTime;
+ }
+ }
+
+ /**
+ * Creates a {@link Runnable} wrapper that gathers execution statistics for the supplied {@link Runnable}.
+ *
+ * @param delegate the <code>Runnable</code> to gather the statistics for.
+ * @return the wrapper.
+ */
+ public Runnable decorate(Runnable delegate) {
+ return new KernelRunnable(delegate);
+ }
+
+ /**
+ * Simple {@link Runnable} that tracks execution statistics for another, wrapped <code>Runnable</code> instance.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Threadsafe.
+ *
+ */
+ private class KernelRunnable implements Runnable {
+
+ private final Runnable delegate;
+
+ private final String applicationName;
+
+ /**
+ * @param delegate
+ */
+ public KernelRunnable(Runnable delegate) {
+ this.delegate = delegate;
+ this.applicationName = accessor.getCurrentApplicationName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ long timeBefore = System.currentTimeMillis();
+ accessor.setCurrentApplicationName(this.applicationName);
+ try {
+ this.delegate.run();
+ } finally {
+ accessor.setCurrentApplicationName(null);
+ ExecutorServiceDelegate outer = ExecutorServiceDelegate.this;
+ long time = System.currentTimeMillis() - timeBefore;
+ synchronized (outer.monitor) {
+ outer.totalExecutionTime += time;
+ }
+ }
+ }
+ }
+
+ /**
+ * Wrapper around {@link TracingService} that handles the service proxy disappearing.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+ private static class ApplicationNameAccessor {
+
+ private final TracingService tracingService;
+
+ public ApplicationNameAccessor(TracingService tracingService) {
+ this.tracingService = tracingService;
+ }
+
+ /**
+ * @return application name
+ * @see TracingService#getCurrentApplicationName()
+ */
+ public String getCurrentApplicationName() {
+ return this.tracingService.getCurrentApplicationName();
+ }
+
+ /**
+ * @param applicationName
+ * @see TracingService#setCurrentApplicationName(String)
+ */
+ public void setCurrentApplicationName(String applicationName) {
+ this.tracingService.setCurrentApplicationName(applicationName);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceInfo.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceInfo.java
new file mode 100644
index 00000000..66393c3b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceInfo.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import javax.management.MXBean;
+
+/**
+ * <p>
+ * Anything that wants to expose information through the service registry about executor services must implement this
+ * interface.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations <strong>must</strong> be threadsafe.
+ *
+ */
+@MXBean
+public interface ExecutorServiceInfo {
+
+ /**
+ * Gets the average execution time of all executed tasks in mili seconds.
+ *
+ * @return the average execution time.
+ */
+ long getAverageExecutionTime();
+
+ /**
+ * Gets the total time spent executing tasks in mili seconds.
+ *
+ * @return the total execution time.
+ */
+ long getExecutionTime();
+
+ /**
+ * Gets the number of active tasks within this executor.
+ *
+ * @return the active task count.
+ */
+ int getActiveCount();
+
+ /**
+ * Gets the current total capacity of the pool.
+ *
+ * @return the current pool size.
+ */
+ int getPoolSize();
+
+ /**
+ * Gets the largest size the pool has ever reached.
+ *
+ * @return the largest pool size.
+ */
+ int getLargestPoolSize();
+
+ /**
+ * Gets the maximum pool size.
+ *
+ * @return the maximum pool size.
+ */
+ int getMaximumPoolSize();
+
+ /**
+ * Gets the type of the pool.
+ *
+ * @return the pool type name.
+ */
+ String getTypeName();
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceStatistics.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceStatistics.java
new file mode 100644
index 00000000..ae61b51a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ExecutorServiceStatistics.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Extension to {@link ExecutorService} that exposes useful metrics. <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations <strong>must</strong> provide for threadsafe access to metrics. However, the timeliness of metric
+ * updates need not be guaranteed.
+ *
+ */
+public interface ExecutorServiceStatistics {
+
+ /**
+ * Gets the average execution time of all executed tasks.
+ *
+ * @return the average execution time.
+ */
+ long getAverageExecutionTime();
+
+ /**
+ * Gets the total time spend executing tasks.
+ *
+ * @return the total execution time.
+ */
+ long getExecutionTime();
+
+ /**
+ * Gets the number of active tasks.
+ *
+ * @return the active task count.
+ */
+ int getActiveCount();
+
+ /**
+ * Gets current size of the pool.
+ *
+ * @return the current pool size.
+ */
+ int getPoolSize();
+
+ /**
+ * Gets the largest size the pool has ever reached.
+ *
+ * @return the largest pool size.
+ */
+ int getLargestPoolSize();
+
+ /**
+ * Gets the maximum pool size.
+ *
+ * @return the maximum pool size.
+ */
+ int getMaximumPoolSize();
+
+ /**
+ * Gets the name of the pool.
+ *
+ * @return the pool name.
+ */
+ String getPoolName();
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelExecutorService.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelExecutorService.java
new file mode 100644
index 00000000..ca6e9063
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelExecutorService.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Extension to {@link ExecutorService} that provides access to metrics about the <code>Executor</code>.<p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Semantics defined in {@link ExecutorService} and {@link ExecutorServiceStatistics}.
+ *
+ */
+public interface KernelExecutorService extends ExecutorService, ExecutorServiceStatistics {
+
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledExecutorService.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledExecutorService.java
new file mode 100644
index 00000000..6a797820
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledExecutorService.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+
+/**
+ * Extension to {@link ScheduledExecutorService} that provides access to metrics about the <code>Executor</code>.<p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Semantics defined in {@link ScheduledExecutorService} and {@link ExecutorServiceStatistics}.
+ *
+ */
+public interface KernelScheduledExecutorService extends ScheduledExecutorService, ExecutorServiceStatistics {
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutor.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutor.java
new file mode 100644
index 00000000..bde19090
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutor.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import static org.eclipse.virgo.kernel.services.concurrent.ThreadPoolUtils.createThreadFactory;
+import static org.eclipse.virgo.kernel.services.concurrent.ThreadPoolUtils.determineHandler;
+
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.eclipse.virgo.kernel.shim.serviceability.TracingService;
+
+
+/**
+ * Extension of {@link ScheduledThreadPoolExecutor} that handles kernel thread decoration.
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public final class KernelScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor implements KernelScheduledExecutorService {
+
+ private final ExecutorServiceDelegate delegate;
+
+ private final String poolName;
+
+ /**
+ * Creates a new <code>KernelScheduledThreadPoolExecutor</code>.
+ *
+ * @param corePoolSize the number of threads in the pool.
+ * @param poolName the name of the pool.
+ * @param tracingService the kernel tracing service
+ * @see ScheduledThreadPoolExecutor#ScheduledThreadPoolExecutor(int, RejectedExecutionHandler)
+ */
+ public KernelScheduledThreadPoolExecutor(int corePoolSize, String poolName, TracingService tracingService) {
+ this(corePoolSize, poolName, tracingService, null);
+ }
+
+ /**
+ * Creates a new <code>KernelScheduledThreadPoolExecutor</code>.
+ *
+ * @param corePoolSize the number of threads in the pool.
+ * @param poolName the name of the pool.
+ * @param tracingService the kernel tracing service
+ * @param handler the {@link RejectedExecutionHandler}.
+ * @see ScheduledThreadPoolExecutor#ScheduledThreadPoolExecutor(int, RejectedExecutionHandler)
+ */
+ public KernelScheduledThreadPoolExecutor(int corePoolSize, String poolName, TracingService tracingService, RejectedExecutionHandler handler) {
+ super(corePoolSize, createThreadFactory(poolName), determineHandler(handler));
+ this.poolName = poolName;
+ this.delegate = new ExecutorServiceDelegate(tracingService);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void execute(Runnable command) {
+ super.execute(this.delegate.decorate(command));
+ }
+
+ /**
+ * Gets an estimate of the average amount of time spent processing successful tasks.
+ *
+ * @return the estimate of time spent.
+ * @see ThreadPoolExecutor#getCompletedTaskCount()
+ */
+ public long getAverageExecutionTime() {
+ return this.delegate.getAverageExecutionTime(getCompletedTaskCount());
+ }
+
+ /**
+ * Gets an estimate of the total amount of time spent processing successful tasks.
+ *
+ * @return the estimate of time spent.
+ * @see ThreadPoolExecutor#getCompletedTaskCount()
+ */
+ public long getExecutionTime() {
+ return this.delegate.getExecutionTime();
+ }
+
+ /**
+ * Get the unique name of the Pool used in this executor service
+ *
+ * {@inheritDoc}
+ */
+ public String getPoolName() {
+ return this.poolName;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutor.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutor.java
new file mode 100644
index 00000000..cf1d1d4d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutor.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import static org.eclipse.virgo.kernel.services.concurrent.ThreadPoolUtils.createThreadFactory;
+import static org.eclipse.virgo.kernel.services.concurrent.ThreadPoolUtils.determineHandler;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.virgo.kernel.shim.serviceability.TracingService;
+
+
+/**
+ * Extension of {@link ThreadPoolExecutor} that handles kernel thread decoration.
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Thread-safe.
+ *
+ */
+public final class KernelThreadPoolExecutor extends ThreadPoolExecutor implements KernelExecutorService {
+
+ private final ExecutorServiceDelegate delegate;
+
+ private final String poolName;
+
+ /**
+ * Creates a new <code>ServerThreadPoolExecutor</code>.
+ *
+ * @param corePoolSize the core size of the pool.
+ * @param maximumPoolSize the maximum size of the pool.
+ * @param keepAliveTime the thread keep alive time.
+ * @param unit the {@link TimeUnit} for the keep alive time.
+ * @param workQueue the work queue.
+ * @param poolName the name of the thread pool.
+ * @param tracingService
+ */
+ public KernelThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
+ BlockingQueue<Runnable> workQueue, String poolName, TracingService tracingService) {
+ this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, poolName, tracingService, null);
+ }
+
+ /**
+ * Creates a new <code>ServerThreadPoolExecutor</code>.
+ *
+ * @param corePoolSize the core size of the pool.
+ * @param maximumPoolSize the maximum size of the pool.
+ * @param keepAliveTime the thread keep alive time.
+ * @param unit the {@link TimeUnit} for the keep alive time.
+ * @param workQueue the work queue.
+ * @param poolName the name of the thread pool.
+ * @param tracingService the kernel tracing service.
+ * @param handler the rejected execution handler. May be <code>null</code>.
+ */
+ public KernelThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
+ BlockingQueue<Runnable> workQueue, String poolName, TracingService tracingService, RejectedExecutionHandler handler) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, createThreadFactory(poolName), determineHandler(handler));
+ this.poolName = poolName;
+ this.delegate = new ExecutorServiceDelegate(tracingService);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void execute(Runnable command) {
+ Runnable decorated = this.delegate.decorate(command);
+ super.execute(decorated);
+ }
+
+ /**
+ * Gets an estimate of the average amount of time spent processing successful tasks.
+ *
+ * @return the estimate of time spent.
+ * @see ThreadPoolExecutor#getCompletedTaskCount()
+ */
+ public long getAverageExecutionTime() {
+ return this.delegate.getAverageExecutionTime(getCompletedTaskCount());
+ }
+
+ /**
+ * Gets an estimate of the total amount of time spent processing successful tasks.
+ *
+ * @return the estimate of time spent.
+ * @see ThreadPoolExecutor#getCompletedTaskCount()
+ */
+ public long getExecutionTime() {
+ return this.delegate.getExecutionTime();
+ }
+
+ /**
+ * Get the unique name of the Pool used in this executor service
+ *
+ * {@inheritDoc}
+ */
+ public String getPoolName() {
+ return this.poolName;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/NamedThreadFactory.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/NamedThreadFactory.java
new file mode 100644
index 00000000..cb073952
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/NamedThreadFactory.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * {@link ThreadFactory} implementation that delegates to the {@link ThreadManager}. Automatic naming of threads in the
+ * pool is handled by this class.<p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+final class NamedThreadFactory implements ThreadFactory {
+
+ private final String poolName;
+
+ private final AtomicInteger threadCount = new AtomicInteger(1);
+
+ /**
+ * Creates a new <code>ThreadManagerPoolThreadFactory</code>.
+ *
+ * @param poolName the name of the thread pool.
+ */
+ public NamedThreadFactory(String poolName) {
+ this.poolName = poolName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Thread newThread(Runnable r) {
+ return new Thread(r, this.poolName + "-thread-" + this.threadCount.getAndIncrement());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/PersistentThreadLocal.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/PersistentThreadLocal.java
new file mode 100644
index 00000000..8b918a75
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/PersistentThreadLocal.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+/**
+ * Marker interface to signify that a {@link ThreadLocal} should not be cleared.<p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * N/A
+ *
+ */
+interface PersistentThreadLocal {
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ThreadPoolUtils.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ThreadPoolUtils.java
new file mode 100644
index 00000000..ad7d631b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/ThreadPoolUtils.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
+
+/**
+ */
+public final class ThreadPoolUtils {
+
+ private static final RejectedExecutionHandler DEFAULT_HANDLER = new AbortPolicy();
+
+ public static ThreadFactory createThreadFactory(String poolName) {
+ return new NamedThreadFactory(poolName);
+ }
+
+ static RejectedExecutionHandler determineHandler(RejectedExecutionHandler handler) {
+ return (handler == null ? DEFAULT_HANDLER : handler);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/diagnostics/ConcurrentLogEvents.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/diagnostics/ConcurrentLogEvents.java
new file mode 100644
index 00000000..41a54447
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/diagnostics/ConcurrentLogEvents.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.diagnostics;
+
+import org.eclipse.virgo.medic.eventlog.Level;
+import org.eclipse.virgo.medic.eventlog.LogEvent;
+
+/**
+ * {@link LogEvent} for the concurrent subsystem.
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public enum ConcurrentLogEvents implements LogEvent {
+
+ DEADLOCK_DETECTED(0, Level.ERROR);
+
+ private static final String PREFIX = "CC";
+
+ private final int code;
+
+ private final Level level;
+
+ private ConcurrentLogEvents(int code, Level level) {
+ this.code = code;
+ this.level = level;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getEventCode() {
+ return String.format("%s%04d%1.1s", PREFIX, this.code, this.level);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Level getLevel() {
+ return this.level;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/ExecutorServiceExporter.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/ExecutorServiceExporter.java
new file mode 100644
index 00000000..1fd32783
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/ExecutorServiceExporter.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.management;
+
+import org.eclipse.virgo.kernel.services.concurrent.ExecutorServiceStatistics;
+
+/**
+ * A utility to encapsulate the management exporting of a {@link ExecutorServiceStatistics} object
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations should be threadsafe
+ *
+ */
+public interface ExecutorServiceExporter {
+
+ void export(ExecutorServiceStatistics executorService);
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporter.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporter.java
new file mode 100644
index 00000000..18b13f18
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporter.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.management;
+
+import java.lang.management.ManagementFactory;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.services.concurrent.ExecutorServiceInfo;
+import org.eclipse.virgo.kernel.services.concurrent.ExecutorServiceStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Implementation of {@link ExecutorServiceExporter} that exports to JMX
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threasafe
+ *
+ */
+public class JmxExecutorServiceExporter implements ExecutorServiceExporter {
+
+ private static final String OBJECT_NAME_PATTERN = "%s:type=Executor Service,name=%s";
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private final Set<ObjectName> exportedExecutorServices = new HashSet<ObjectName>();
+
+ private final String managementDomain;
+
+ public JmxExecutorServiceExporter(String managementDomain) {
+ this.managementDomain = managementDomain;
+ }
+
+ public void export(ExecutorServiceStatistics executorService) {
+ try {
+ ObjectName name = new ObjectName(String.format(OBJECT_NAME_PATTERN, this.managementDomain, executorService.getPoolName()));
+ ExecutorServiceInfo info = new StandardExecutorServiceInfo(executorService);
+ this.server.registerMBean(info, name);
+
+ synchronized (this.exportedExecutorServices) {
+ this.exportedExecutorServices.add(name);
+ }
+ } catch (JMException e) {
+ this.logger.warn(String.format("Unable to register executor service %s for management", executorService), e);
+ }
+ }
+
+ public void destroy() {
+ synchronized (this.exportedExecutorServices) {
+ for (ObjectName exportedExecutorService : this.exportedExecutorServices) {
+ try {
+ this.server.unregisterMBean(exportedExecutorService);
+ } catch (JMException e) {
+ this.logger.warn(String.format("Unable to unregister executor service %s from management", exportedExecutorService), e);
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/StandardExecutorServiceInfo.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/StandardExecutorServiceInfo.java
new file mode 100644
index 00000000..15e02ace
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/management/StandardExecutorServiceInfo.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.management;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.eclipse.virgo.kernel.services.concurrent.ExecutorServiceInfo;
+import org.eclipse.virgo.kernel.services.concurrent.ExecutorServiceStatistics;
+
+
+/**
+ * Standard implementation of {@link ExecutorServiceInfo}. Maintains a {@link WeakReference} to the underlying
+ * {@link ExecutorServiceStatistics} to prevent pinning the executor in memory.<p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public class StandardExecutorServiceInfo implements ExecutorServiceInfo {
+
+ private final Reference<ExecutorServiceStatistics> managedExecutorService;
+
+ /**
+ * Constructor that deals with figuring out what kind of service there is and setting the references accordingly.
+ *
+ * @param service the {@link ExecutorServiceStatistics} being exposed.
+ */
+ public StandardExecutorServiceInfo(ExecutorServiceStatistics service) {
+ this.managedExecutorService = new WeakReference<ExecutorServiceStatistics>(service);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getAverageExecutionTime() {
+ ExecutorServiceStatistics executorService = this.managedExecutorService.get();
+ return executorService == null ? -1 : executorService.getAverageExecutionTime();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getExecutionTime() {
+ ExecutorServiceStatistics executorService = this.managedExecutorService.get();
+ return executorService == null ? -1 : executorService.getExecutionTime();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getPoolSize() {
+ ExecutorServiceStatistics executorService = this.managedExecutorService.get();
+ return executorService == null ? -1 : executorService.getPoolSize();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getLargestPoolSize() {
+ ExecutorServiceStatistics executorService = this.managedExecutorService.get();
+ return executorService == null ? -1 : executorService.getLargestPoolSize();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getTypeName() {
+ ExecutorServiceStatistics executorService = this.managedExecutorService.get();
+ if(executorService == null) {
+ return null;
+ } else {
+ return (executorService instanceof ScheduledExecutorService ? ScheduledExecutorService.class.getSimpleName() : ExecutorService.class.getSimpleName());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getActiveCount() {
+ ExecutorServiceStatistics executorService = this.managedExecutorService.get();
+ return executorService == null ? -1 : executorService.getActiveCount();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getMaximumPoolSize() {
+ ExecutorServiceStatistics executorService = this.managedExecutorService.get();
+ return executorService == null ? -1 : executorService.getMaximumPoolSize();
+ }
+
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyser.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyser.java
new file mode 100644
index 00000000..bd101671
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyser.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.monitor;
+
+import java.lang.Thread.State;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Analyses any deadlocks present in the VM and creates a description of the cycles.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public class DeadlockAnalyser {
+
+ /**
+ * Result when there are no deadlocks.
+ */
+ private static final Deadlock[] NULL_RESULT = new Deadlock[0];
+
+ /**
+ * The VM {@link ThreadMXBean}.
+ */
+ private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+
+ /**
+ * Identifies deadlocks in the currently running {@link Thread Threads}.
+ *
+ * @return the deadlocks; never <code>null</code>.
+ */
+ public Deadlock[] findDeadlocks() {
+ long[] deadlockedThreads = this.threadBean.findMonitorDeadlockedThreads();
+ if (deadlockedThreads == null || deadlockedThreads.length == 0) {
+ return NULL_RESULT;
+ }
+
+ Map<Long, ThreadInfo> threadInfoMap = createThreadInfoMap(deadlockedThreads);
+ Set<LinkedHashSet<ThreadInfo>> cycles = calculateCycles(threadInfoMap);
+ Set<LinkedHashSet<ThreadInfo>> chains = calculateCycleDeadlockChains(threadInfoMap, cycles);
+ cycles.addAll(chains);
+ return createDeadlockDescriptions(cycles);
+ }
+
+ /**
+ * Creates {@link Deadlock} objects for each cycle in the supplied set.
+ *
+ * @param cycles the cycles.
+ * @return the <code>Deadlocks</code>.
+ */
+ private Deadlock[] createDeadlockDescriptions(Set<LinkedHashSet<ThreadInfo>> cycles) {
+ Deadlock[] result = new Deadlock[cycles.size()];
+ int count = 0;
+ for (Set<ThreadInfo> cycle : cycles) {
+ ThreadInfo[] asArray = cycle.toArray(new ThreadInfo[cycle.size()]);
+ Deadlock d = new Deadlock(asArray);
+ result[count++] = d;
+ }
+ return result;
+ }
+
+ /**
+ * Calculates the cycles in the supplied {@link ThreadInfo} map. A cycle is represented as a {@link LinkedHashSet}
+ * of <code>ThreadInfo</code> objects. The order of the items in the <code>LinkedHashSet</code> reflects cycle
+ * order.
+ *
+ * @param threadInfoMap the <code>ThreadInfo</code> map.
+ * @return all the cycles.
+ */
+ private Set<LinkedHashSet<ThreadInfo>> calculateCycles(Map<Long, ThreadInfo> threadInfoMap) {
+ Set<LinkedHashSet<ThreadInfo>> cycles = new HashSet<LinkedHashSet<ThreadInfo>>();
+ for (Map.Entry<Long, ThreadInfo> entry : threadInfoMap.entrySet()) {
+ LinkedHashSet<ThreadInfo> cycle = new LinkedHashSet<ThreadInfo>();
+
+ ThreadInfo t = entry.getValue();
+ while (!cycle.contains(t)) {
+ cycle.add(t);
+ t = threadInfoMap.get(t.getLockOwnerId());
+ }
+ if (!cycles.contains(cycle)) {
+ cycles.add(cycle);
+ }
+ }
+
+ return cycles;
+ }
+
+ /**
+ * Calculates deadlock chains where the deadlock occurs from a chain of threads waiting on some lock that is part of
+ * a deadlock cycle. A cycle is represented as a {@link LinkedHashSet} of <code>ThreadInfo</code> objects. The order
+ * of the items in the <code>LinkedHashSet</code> reflects chain order.
+ *
+ * @param threadInfoMap the <code>ThreadInfo</code> map.
+ * @param cycles the known deadlock cycles.
+ * @return the deadlock chains.
+ */
+ private Set<LinkedHashSet<ThreadInfo>> calculateCycleDeadlockChains(Map<Long, ThreadInfo> threadInfoMap, Set<LinkedHashSet<ThreadInfo>> cycles) {
+ ThreadInfo[] allThreads = this.threadBean.getThreadInfo(this.threadBean.getAllThreadIds());
+ Set<LinkedHashSet<ThreadInfo>> deadlockChain = new HashSet<LinkedHashSet<ThreadInfo>>();
+ Set<Long> knownDeadlockedThreads = threadInfoMap.keySet();
+ for (ThreadInfo threadInfo : allThreads) {
+ State state = threadInfo.getThreadState();
+ if (state == State.BLOCKED && !knownDeadlockedThreads.contains(threadInfo.getThreadId())) {
+ for (LinkedHashSet<ThreadInfo> cycle : cycles) {
+ if (cycle.contains(threadInfoMap.get(threadInfo.getLockOwnerId()))) {
+ LinkedHashSet<ThreadInfo> chain = new LinkedHashSet<ThreadInfo>();
+ ThreadInfo node = threadInfo;
+ while (!chain.contains(node)) {
+ chain.add(node);
+ node = threadInfoMap.get(node.getLockOwnerId());
+ }
+ deadlockChain.add(chain);
+ }
+ }
+ }
+ }
+ return deadlockChain;
+ }
+
+ /**
+ * Creates a mapping of <code>ThreadId +> ThreadInfo</code> for the deadlocked threads.
+ *
+ * @param threadIds the deadlocked thread ids
+ * @return the mapping.
+ */
+ private Map<Long, ThreadInfo> createThreadInfoMap(long[] threadIds) {
+ ThreadInfo[] threadInfos = this.threadBean.getThreadInfo(threadIds);
+
+ Map<Long, ThreadInfo> threadInfoMap = new HashMap<Long, ThreadInfo>();
+ for (ThreadInfo threadInfo : threadInfos) {
+ threadInfoMap.put(threadInfo.getThreadId(), threadInfo);
+ }
+ return threadInfoMap;
+ }
+
+ /**
+ * Describes a deadlock of two or more threads.
+ *
+ */
+ public static final class Deadlock {
+
+ private final ThreadInfo[] members;
+
+ private final String description;
+
+ private final Set<Long> memberIds;
+
+ /**
+ * Creates a new {@link Deadlock}.
+ *
+ * @param members the members of the deadlock in cycle order.
+ */
+ private Deadlock(ThreadInfo[] members) {
+ this.members = members;
+ this.memberIds = new HashSet<Long>(members.length);
+ StringBuilder sb = new StringBuilder();
+ for (int x = 0; x < members.length; x++) {
+ ThreadInfo ti = members[x];
+ sb.append(ti.getThreadName());
+ if (x < members.length) {
+ sb.append(" > ");
+ }
+
+ if (x == members.length - 1) {
+ sb.append(ti.getLockOwnerName());
+ }
+ this.memberIds.add(ti.getThreadId());
+ }
+ this.description = sb.toString();
+ }
+
+ /**
+ * Gets the members of the deadlock in cycle order.
+ *
+ * @return the members of the deadlock.
+ */
+ public ThreadInfo[] getMembers() {
+ return this.members.clone();
+ }
+
+ @Override
+ public String toString() {
+ return this.description;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + this.memberIds.hashCode();
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Deadlock other = (Deadlock) obj;
+ return other.memberIds.equals(this.memberIds);
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockMonitor.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockMonitor.java
new file mode 100644
index 00000000..0304dac4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockMonitor.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.monitor;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.virgo.kernel.services.concurrent.diagnostics.ConcurrentLogEvents;
+import org.eclipse.virgo.kernel.services.concurrent.monitor.DeadlockAnalyser.Deadlock;
+import org.eclipse.virgo.medic.dump.DumpGenerator;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.util.math.Sets;
+
+/**
+ * Monitors all running {@link Thread Threads} and triggers a dump when a deadlock is detected.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+final class DeadlockMonitor {
+
+ private static final int PERIOD = 10;
+
+ private static final TimeUnit UNIT = TimeUnit.SECONDS;
+
+ private final ScheduledExecutorService executorService;
+
+ private final DumpGenerator dumpGenerator;
+
+ private final EventLogger eventLogger;
+
+ private volatile ScheduledFuture<?> future;
+
+ /**
+ * Creates a new <code>DeadlockMonitor</code>.
+ *
+ * @param executorService the <code>ScheduledExecutorService</code>
+ * @param dumpGenerator the @{link {@link DumpGenerator} to trigger a dump.
+ * @param eventLogger
+ */
+ public DeadlockMonitor(ScheduledExecutorService executorService, DumpGenerator dumpGenerator, EventLogger eventLogger) {
+ this.executorService = executorService;
+ this.dumpGenerator = dumpGenerator;
+ this.eventLogger = eventLogger;
+ }
+
+ /**
+ * Starts the deadlock monitor.
+ */
+ public void start() {
+ this.future = this.executorService.scheduleAtFixedRate(new DeadlockMonitorTask(this.dumpGenerator, this.eventLogger), PERIOD, PERIOD, UNIT);
+ }
+
+ /**
+ * Stops the deadlock monitor.
+ */
+ public void stop() {
+ if (this.executorService != null) {
+ this.executorService.shutdown();
+ }
+
+ if (this.future != null) {
+ this.future.cancel(true);
+ }
+ }
+
+ /**
+ * Task for monitoring threads for deadlocks.
+ * <p/>
+ */
+ private static class DeadlockMonitorTask implements Runnable {
+
+ private final DeadlockAnalyser analyser = new DeadlockAnalyser();
+
+ private final EventLogger eventLogger;
+
+ private final Set<Deadlock> lastSeenDeadlocks = new HashSet<Deadlock>();
+
+ private final Object monitor = new Object();
+
+ private final DumpGenerator dumpGenerator;
+
+ /**
+ * Creates a new <code>DeadlockMonitorTask</code>.
+ *
+ * @param dumpGenerator the {@link DumpGenerator} to use.
+ * @param eventLogger
+ */
+ public DeadlockMonitorTask(DumpGenerator dumpGenerator, EventLogger eventLogger) {
+ this.dumpGenerator = dumpGenerator;
+ this.eventLogger = eventLogger;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ synchronized (this.monitor) {
+ Deadlock[] deadlocks = this.analyser.findDeadlocks();
+ if (deadlocks != null && deadlocks.length > 0) {
+ Set<Deadlock> asSet = Sets.asSet(deadlocks);
+ if (!asSet.equals(this.lastSeenDeadlocks)) {
+ this.eventLogger.log(ConcurrentLogEvents.DEADLOCK_DETECTED);
+ this.dumpGenerator.generateDump("deadlock");
+ this.lastSeenDeadlocks.clear();
+ this.lastSeenDeadlocks.addAll(asSet);
+ }
+ } else {
+ this.lastSeenDeadlocks.clear();
+ }
+ }
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/internal/KernelServicesLogEvents.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/internal/KernelServicesLogEvents.java
new file mode 100644
index 00000000..e72dd2a4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/internal/KernelServicesLogEvents.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.internal;
+
+import org.eclipse.virgo.kernel.serviceability.LogEventDelegate;
+import org.eclipse.virgo.medic.eventlog.Level;
+import org.eclipse.virgo.medic.eventlog.LogEvent;
+
+/**
+ * Defines all the {@link LogEvent LogEvents} for the kernel services bundle.
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Implementation is immutable.
+ *
+ */
+public enum KernelServicesLogEvents implements LogEvent {
+
+ KERNEL_REPOSITORY_CHAIN_EMPTY(1, Level.INFO), //
+
+ KERNEL_REPOSITORY_CHAIN_ENTRY_NOT_VALID(2, Level.ERROR);
+
+ private static final String PREFIX = "KS";
+
+ private final LogEventDelegate delegate;
+
+ private KernelServicesLogEvents(int code, Level level) {
+ this.delegate = new LogEventDelegate(PREFIX, code, level);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getEventCode() {
+ return this.delegate.getEventCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Level getLevel() {
+ return this.delegate.getLevel();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepository.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepository.java
new file mode 100644
index 00000000..c0c966cb
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepository.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.repository.internal;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.virgo.repository.Query;
+import org.eclipse.virgo.repository.Repository;
+import org.eclipse.virgo.repository.RepositoryAwareArtifactDescriptor;
+import org.eclipse.virgo.util.osgi.VersionRange;
+
+/**
+ * TODO Document EmptyRepository
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * TODO Document concurrent semantics of EmptyRepository
+ *
+ */
+public class EmptyRepository implements Repository {
+
+ private static final Query EMPTY_QUERY = new EmptyQuery();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Query createQuery(String key, String value) {
+ return EMPTY_QUERY;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Query createQuery(String key, String value, Map<String, Set<String>> properties) {
+ return EMPTY_QUERY;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RepositoryAwareArtifactDescriptor get(String type, String name, VersionRange versionRange) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return "empty";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stop() {
+ }
+
+ private static final class EmptyQuery implements Query {
+
+ /**
+ * {@inheritDoc}
+ */
+ public Query addFilter(String name, String value) {
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Query addFilter(String name, String value, Map<String, Set<String>> properties) {
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<RepositoryAwareArtifactDescriptor> run() {
+ return Collections.<RepositoryAwareArtifactDescriptor> emptySet();
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBean.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBean.java
new file mode 100644
index 00000000..aef14062
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBean.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.repository.internal;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.springframework.beans.factory.FactoryBean;
+
+import org.eclipse.virgo.kernel.services.internal.KernelServicesLogEvents;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.Repository;
+import org.eclipse.virgo.repository.RepositoryCreationException;
+import org.eclipse.virgo.repository.RepositoryFactory;
+import org.eclipse.virgo.repository.configuration.PropertiesRepositoryConfigurationReader;
+import org.eclipse.virgo.repository.configuration.RepositoryConfiguration;
+import org.eclipse.virgo.repository.configuration.RepositoryConfigurationException;
+import org.eclipse.virgo.util.math.OrderedPair;
+
+public final class RepositoryFactoryBean implements FactoryBean<Repository> {
+
+ private final Properties repositoryProperties;
+
+ private final EventLogger eventLogger;
+
+ private final RepositoryFactory repositoryFactory;
+
+ private volatile Repository repository;
+
+ private final File workDirectory;
+
+ private final Set<ArtifactBridge> artifactBridges;
+
+ private final String mBeanDomain;
+
+ public RepositoryFactoryBean(Properties repositoryProperties, EventLogger eventLogger, RepositoryFactory repositoryFactory, File workDirectory,
+ Set<ArtifactBridge> artifactBridges, String mBeanDomain) {
+ this.repositoryProperties = repositoryProperties;
+ this.eventLogger = eventLogger;
+ this.repositoryFactory = repositoryFactory;
+ this.workDirectory = workDirectory;
+ this.artifactBridges = artifactBridges;
+ this.mBeanDomain = mBeanDomain;
+ }
+
+ public Repository getObject() throws Exception {
+ if (this.repository == null) {
+ this.repository = createRepository();
+ }
+ return this.repository;
+ }
+
+ public Class<? extends Repository> getObjectType() {
+ return Repository.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public void destroy() {
+ Repository localRepository = this.repository;
+ if (localRepository != null) {
+ this.repository = null;
+ localRepository.stop();
+ }
+ }
+
+ private Repository createRepository() throws RepositoryConfigurationException, RepositoryCreationException {
+
+ PropertiesRepositoryConfigurationReader configurationReader = new PropertiesRepositoryConfigurationReader(this.workDirectory,
+ this.artifactBridges, this.eventLogger, this.mBeanDomain);
+
+ OrderedPair<Map<String, RepositoryConfiguration>, List<String>> configurations = configurationReader.readConfiguration(this.repositoryProperties);
+ Map<String, RepositoryConfiguration> configurationMap = configurations.getFirst();
+ List<String> chainList = configurations.getSecond();
+
+ if (chainList.isEmpty()) {
+ this.eventLogger.log(KernelServicesLogEvents.KERNEL_REPOSITORY_CHAIN_EMPTY);
+ return new EmptyRepository(); // no chain
+ }
+
+ List<RepositoryConfiguration> repositoryConfigurationChain = new ArrayList<RepositoryConfiguration>(chainList.size());
+ for (String repositoryName : chainList) {
+ RepositoryConfiguration repositoryConfiguration = configurationMap.get(repositoryName);
+
+ if (repositoryConfiguration == null) {
+ this.eventLogger.log(KernelServicesLogEvents.KERNEL_REPOSITORY_CHAIN_ENTRY_NOT_VALID, repositoryName);
+ throw new RepositoryConfigurationException("Cannot resolve repository '" + repositoryName + "' in chain.");
+ }
+ repositoryConfigurationChain.add(repositoryConfiguration);
+ }
+ return repositoryFactory.createRepository(repositoryConfigurationChain);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/StandardWorkArea.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/StandardWorkArea.java
new file mode 100644
index 00000000..12ca9e4f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/StandardWorkArea.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.work;
+
+import java.io.File;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.virgo.util.io.PathReference;
+
+/**
+ * Standard implementation of {@link WorkArea}.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Threadsafe.
+ *
+ */
+final class StandardWorkArea implements WorkArea {
+
+ private final PathReference workDirectory;
+
+ private final Bundle owner;
+
+ /**
+ * Creates a new <code>StandardWorkAreaManager</code>.
+ *
+ * @param workDirectory the root work directory
+ * @param owner the owning <code>Bundle</code>
+ */
+ public StandardWorkArea(File workDirectory, Bundle owner) {
+ this.owner = owner;
+ this.workDirectory = new PathReference(workDirectory).newChild(createOwnerDirectoryName(owner));
+ this.workDirectory.createDirectory();
+ }
+
+ private String createOwnerDirectoryName(Bundle owner) {
+ return String.format("%s_%s", owner.getSymbolicName(), owner.getVersion());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Bundle getOwner() {
+ return this.owner;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PathReference getWorkDirectory() {
+ return this.workDirectory;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkArea.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkArea.java
new file mode 100644
index 00000000..3a4bc47a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkArea.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.work;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.virgo.util.io.PathReference;
+
+/**
+ * Controls access to the work area.<p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations <strong>must</strong> be threadsafe.
+ *
+ */
+public interface WorkArea {
+
+ /**
+ * Gets the {@link Bundle} that owns this section of the work area.
+ * @return the owning <code>Bundle</code>.
+ */
+ Bundle getOwner();
+
+ /**
+ * Gets the work directory for this work area.
+ *
+ * @return a {@link PathReference} to the work directory.
+ */
+ PathReference getWorkDirectory();
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactory.java b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactory.java
new file mode 100644
index 00000000..31657aba
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactory.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.work;
+
+import java.io.File;
+
+import org.eclipse.virgo.kernel.serviceability.NonNull;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * {@link ServiceFactory} that creates a {@link WorkArea} for a given {@link Bundle}. Bundles need only to import a
+ * <code>WorkArea</code> servicein their module context file to get access to the correct work area location.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public final class WorkAreaServiceFactory implements ServiceFactory {
+
+ private final File workDirectory;
+
+ public WorkAreaServiceFactory(@NonNull File workDirectory) {
+ this.workDirectory = workDirectory;
+ }
+
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ return new StandardWorkArea(this.workDirectory, bundle);
+ }
+
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/main/resources/EventLogMessages.properties b/org.eclipse.virgo.kernel.services/src/main/resources/EventLogMessages.properties
new file mode 100644
index 00000000..ae8d78c4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/resources/EventLogMessages.properties
@@ -0,0 +1,4 @@
+KS0001I = Kernel repository chain is empty.
+KS0002E = Cannot resolve repository chain entry '{}'.
+
+CC0000E = Deadlock detected. Generating dump.
diff --git a/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/concurrent-context.xml b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/concurrent-context.xml
new file mode 100644
index 00000000..453fb92d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/concurrent-context.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd
+ http://www.springframework.org/schema/util
+ http://www.springframework.org/schema/util/spring-util-2.5.xsd
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+
+ <reference id="dumpGenerator" interface="org.eclipse.virgo.medic.dump.DumpGenerator"/>
+
+ <reference id="eventLogger" interface="org.eclipse.virgo.medic.eventlog.EventLogger"/>
+
+ <reference id="tracingService" interface="org.eclipse.virgo.kernel.shim.serviceability.TracingService" />
+
+ <beans:bean id="exporter" class="org.eclipse.virgo.kernel.services.concurrent.management.JmxExecutorServiceExporter" destroy-method="destroy">
+ <beans:constructor-arg value="${domain}"/>
+ </beans:bean>
+
+ <beans:bean id="deadlockMonitor" class="org.eclipse.virgo.kernel.services.concurrent.monitor.DeadlockMonitor" init-method="start" destroy-method="stop">
+ <beans:constructor-arg>
+ <beans:bean class="org.eclipse.virgo.kernel.services.concurrent.KernelScheduledThreadPoolExecutor">
+ <beans:constructor-arg value="1"/>
+ <beans:constructor-arg value="deadlock-monitor"/>
+ <beans:constructor-arg ref="tracingService"/>
+ </beans:bean>
+ </beans:constructor-arg>
+ <beans:constructor-arg ref="dumpGenerator"/>
+ <beans:constructor-arg ref="eventLogger"/>
+ </beans:bean>
+</beans:beans>
diff --git a/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/configuration-context.xml b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/configuration-context.xml
new file mode 100644
index 00000000..b368be7f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/configuration-context.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:osgi="http://www.springframework.org/schema/osgi"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:osgi-compendium="http://www.springframework.org/schema/osgi-compendium"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-1.2.xsd
+ http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium-1.2.xsd">
+
+ <osgi-compendium:cm-properties id="kernelConfig" persistent-id="org.eclipse.virgo.kernel"/>
+
+ <context:property-placeholder properties-ref="kernelConfig"/>
+
+</beans>
diff --git a/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/io-context.xml b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/io-context.xml
new file mode 100644
index 00000000..c0b46830
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/io-context.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:beans="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+ <beans:bean id="workAreaFactory" class="org.eclipse.virgo.kernel.services.work.WorkAreaServiceFactory">
+ <beans:constructor-arg value="${work.directory}"/>
+ </beans:bean>
+
+ <beans:bean id="kernelWorkArea" class="org.eclipse.virgo.kernel.services.work.StandardWorkArea">
+ <beans:constructor-arg value="${work.directory}"/>
+ <beans:constructor-arg value="#{bundleContext.bundle}"/>
+ </beans:bean>
+
+ <service interface="org.eclipse.virgo.kernel.services.work.WorkArea" ref="workAreaFactory"/>
+</beans:beans>
diff --git a/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/repository-context.xml b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/repository-context.xml
new file mode 100644
index 00000000..f802edaa
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/main/resources/META-INF/spring/repository-context.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:osgi="http://www.springframework.org/schema/osgi"
+ xmlns:osgi-compendium="http://www.springframework.org/schema/osgi-compendium"
+ xsi:schemaLocation="http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-1.2.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium-1.2.xsd">
+
+ <bean id="repository" class="org.eclipse.virgo.kernel.services.repository.internal.RepositoryFactoryBean" destroy-method="destroy">
+ <constructor-arg>
+ <osgi-compendium:cm-properties persistent-id="org.eclipse.virgo.repository"/>
+ </constructor-arg>
+ <constructor-arg ref="eventLogger"/>
+ <constructor-arg ref="repositoryFactory"/>
+ <constructor-arg value="${work.directory}"/>
+ <constructor-arg >
+ <set>
+ <ref bean="bundleBridge"/>
+ <ref bean="libraryBridge"/>
+ <ref bean="parBridge"/>
+ <ref bean="planBridge"/>
+ <ref bean="propertiesBridge"/>
+ </set>
+ </constructor-arg>
+ <constructor-arg value="${domain}"/>
+ </bean>
+
+ <bean id="bundleBridge" class="org.eclipse.virgo.kernel.artifact.bundle.BundleBridge">
+ <constructor-arg ref="hashGenerator"/>
+ </bean>
+ <osgi:service ref="bundleBridge" interface="org.eclipse.virgo.repository.ArtifactBridge"/>
+
+ <bean id="libraryBridge" class="org.eclipse.virgo.kernel.artifact.library.LibraryBridge">
+ <constructor-arg ref="hashGenerator"/>
+ </bean>
+ <osgi:service ref="libraryBridge" interface="org.eclipse.virgo.repository.ArtifactBridge"/>
+
+ <bean id="parBridge" class="org.eclipse.virgo.kernel.artifact.par.ParBridge">
+ <constructor-arg ref="hashGenerator"/>
+ </bean>
+ <osgi:service ref="parBridge" interface="org.eclipse.virgo.repository.ArtifactBridge"/>
+
+ <bean id="planBridge" class="org.eclipse.virgo.kernel.artifact.plan.PlanBridge">
+ <constructor-arg ref="hashGenerator"/>
+ </bean>
+ <osgi:service ref="planBridge" interface="org.eclipse.virgo.repository.ArtifactBridge"/>
+
+ <bean id="propertiesBridge" class="org.eclipse.virgo.kernel.artifact.properties.PropertiesBridge">
+ <constructor-arg ref="hashGenerator"/>
+ </bean>
+ <osgi:service ref="propertiesBridge" interface="org.eclipse.virgo.repository.ArtifactBridge"/>
+
+ <osgi:reference id="repositoryFactory" interface="org.eclipse.virgo.repository.RepositoryFactory" />
+
+ <osgi:reference id="eventLogger" interface="org.eclipse.virgo.medic.eventlog.EventLogger" />
+
+ <osgi:service ref="repository" interface="org.eclipse.virgo.repository.Repository"/>
+
+ <osgi:reference id="hashGenerator" interface="org.eclipse.virgo.repository.HashGenerator"/>
+
+</beans>
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/AbstractExecutorTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/AbstractExecutorTests.java
new file mode 100644
index 00000000..3841900e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/AbstractExecutorTests.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.junit.Test;
+
+/**
+ */
+public abstract class AbstractExecutorTests {
+
+ /*
+ * Use Futures here so we can get the AssertionErrors back in the JUnit thread.
+ */
+
+ @Test public void testManuallyNamed() throws Throwable {
+ submitAndAssert(getNamed("TestPool"), new Runnable() {
+
+ public void run() {
+ assertTrue(Thread.currentThread().getName().startsWith("TestPool"));
+ }
+
+ });
+ }
+
+ @Test public void testThreadLocalCleared() throws Throwable {
+
+ final ThreadLocal<String> t = new ThreadLocal<String>();
+ this.getExecutor().execute(new Runnable() {
+
+ public void run() {
+ t.set("foo");
+ }
+
+ });
+
+ submitAndAssert(this.getExecutor(), new Runnable() {
+
+ public void run() {
+ assertNull("ThreadLocal should be null", t.get());
+ }
+
+ });
+
+ }
+
+ private void submitAndAssert(ExecutorService executor, Runnable task) throws Throwable {
+ Future<?> f = executor.submit(task);
+ assertFuture(f);
+ }
+
+ private void assertFuture(Future<?> future) throws Throwable {
+ try {
+ future.get();
+ } catch (ExecutionException ex) {
+ throw ex.getCause();
+ }
+ }
+
+ protected abstract ExecutorService getExecutor();
+
+ protected abstract ExecutorService getNamed(String name);
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutorTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutorTests.java
new file mode 100644
index 00000000..ebc0595e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelScheduledThreadPoolExecutorTests.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import java.util.concurrent.ExecutorService;
+
+import org.eclipse.virgo.kernel.services.concurrent.KernelScheduledThreadPoolExecutor;
+import org.eclipse.virgo.kernel.shim.serviceability.TracingService;
+
+
+/**
+ */
+public class KernelScheduledThreadPoolExecutorTests extends AbstractExecutorTests {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ExecutorService getExecutor() {
+ return getNamed("foo");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ExecutorService getNamed(String name) {
+ return new KernelScheduledThreadPoolExecutor(1, name, new StubTracingService());
+ }
+
+ private final class StubTracingService implements TracingService {
+
+ public String getCurrentApplicationName() {
+ return null;
+ }
+
+ public void setCurrentApplicationName(String applicationName) {
+ }
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutorTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutorTests.java
new file mode 100644
index 00000000..4fd23b17
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/KernelThreadPoolExecutorTests.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.virgo.kernel.services.concurrent.KernelThreadPoolExecutor;
+import org.eclipse.virgo.kernel.shim.serviceability.TracingService;
+import org.junit.Test;
+
+
+/**
+ */
+public class KernelThreadPoolExecutorTests extends AbstractExecutorTests {
+
+ private final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
+
+ private final StubTracingService tracingService = new StubTracingService();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KernelThreadPoolExecutor getExecutor() {
+ return getNamed(null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KernelThreadPoolExecutor getNamed(String name) {
+ return new KernelThreadPoolExecutor(1, 1, 5, TimeUnit.SECONDS, this.queue, name, this.tracingService);
+ }
+
+ @Test
+ public void statisticsOnFail() throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ KernelThreadPoolExecutor executor = getExecutor();
+ executor.execute(new Runnable() {
+
+ public void run() {
+ try {
+ throw new RuntimeException("foo");
+ } finally {
+ latch.countDown();
+ }
+ }
+
+ });
+ latch.await();
+ assertEquals(0, executor.getCompletedTaskCount());
+ }
+
+ @Test
+ public void statisticsOnSuccess() throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ KernelThreadPoolExecutor executor = getExecutor();
+ executor.execute(new Runnable() {
+
+ public void run() {
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ latch.countDown();
+ }
+ }
+
+ });
+ latch.await();
+ Thread.sleep(100);
+ assertEquals(1, executor.getCompletedTaskCount());
+ assertTrue(executor.getAverageExecutionTime() > 0);
+ assertTrue(executor.getExecutionTime() > 0);
+ }
+
+ @Test
+ public void traceNamePropagated() throws InterruptedException {
+ this.tracingService.setCurrentApplicationName("foo");
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ KernelThreadPoolExecutor executor = getExecutor();
+ executor.execute(new Runnable() {
+
+ public void run() {
+ if ("foo".equals(tracingService.getCurrentApplicationName())) {
+ latch.countDown();
+ }
+ }
+
+ });
+ boolean result = latch.await(2, TimeUnit.SECONDS);
+ assertTrue(result);
+ }
+
+ private final class StubTracingService implements TracingService {
+
+ private String applicationName;
+
+ public String getCurrentApplicationName() {
+ return applicationName;
+ }
+
+ public void setCurrentApplicationName(String applicationName) {
+ this.applicationName = applicationName;
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporterTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporterTests.java
new file mode 100644
index 00000000..ce0fcee2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/management/JmxExecutorServiceExporterTests.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.management;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.services.concurrent.ExecutorServiceStatistics;
+import org.eclipse.virgo.kernel.services.concurrent.management.JmxExecutorServiceExporter;
+import org.junit.Test;
+
+
+
+/**
+ */
+public class JmxExecutorServiceExporterTests {
+
+ @Test
+ public void testExportAndDestroy() throws Exception {
+ JmxExecutorServiceExporter exporter = new JmxExecutorServiceExporter("domain");
+ ExecutorServiceStatistics stats = new DummyStatistics();
+ exporter.export(stats);
+
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ ObjectInstance instance = getInstance(server);
+ assertNotNull(instance);
+
+ exporter.destroy();
+ try {
+ instance = getInstance(server);
+ fail("Instance should've been unregistered");
+ } catch (Exception e) {
+ }
+
+ }
+
+ private ObjectInstance getInstance(MBeanServer server) throws InstanceNotFoundException, MalformedObjectNameException {
+ return server.getObjectInstance(new ObjectName("domain:type=Executor Service,name=dummy"));
+ }
+
+ private static class DummyStatistics implements ExecutorServiceStatistics {
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getActiveCount() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getAverageExecutionTime() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getExecutionTime() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getLargestPoolSize() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getMaximumPoolSize() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPoolName() {
+ return "dummy";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getPoolSize() {
+ return 0;
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyserTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyserTests.java
new file mode 100644
index 00000000..4f52af41
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockAnalyserTests.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.monitor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.virgo.kernel.services.concurrent.monitor.DeadlockAnalyser;
+import org.eclipse.virgo.kernel.services.concurrent.monitor.DeadlockAnalyser.Deadlock;
+import org.junit.Test;
+
+
+/**
+ */
+public class DeadlockAnalyserTests {
+
+ @Test public void deadlocks() {
+ DeadlockAnalyser da = new DeadlockAnalyser();
+ Deadlock[] before = da.findDeadlocks();
+
+ DeadlockCreatorMBean dc = new DeadlockCreator();
+ dc.createDeadlock(2, 0);
+ dc.createDeadlock(3, 0);
+ dc.createDeadlock(4, 2);
+
+ Deadlock[] deadlocks = da.findDeadlocks();
+ assertNotNull(deadlocks);
+ assertEquals(5 + before.length, deadlocks.length);
+ boolean seen2 = false;
+ boolean seen3 = false;
+ boolean seen4 = false;
+ for (Deadlock deadlock : deadlocks) {
+ switch (deadlock.getMembers().length) {
+ case 2:
+ seen2 = true;
+ break;
+ case 3:
+ seen3 = true;
+ break;
+ case 4:
+ seen4 = true;
+ break;
+ }
+ }
+ assertTrue(seen2);
+ assertTrue(seen3);
+ assertTrue(seen4);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreator.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreator.java
new file mode 100644
index 00000000..6eff409d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreator.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.monitor;
+
+import java.lang.Thread.State;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ */
+public class DeadlockCreator implements DeadlockCreatorMBean {
+
+ public Thread[] createDeadlock(int threadCount, int extraneousCount) {
+ CountDownLatch latch = new CountDownLatch(threadCount);
+ Object[] monitors = new Object[threadCount];
+
+ for (int x = 0; x < threadCount; x++) {
+ monitors[x] = new Object();
+ }
+
+ Thread[] threads = new Thread[threadCount];
+ for (int x = 0; x < threadCount; x++) {
+ int f = x;
+ int s = x == threadCount - 1 ? 0 : x + 1;
+ threads[x] = new Thread(new DeadlockRunnable(latch, monitors[f], monitors[s]));
+ threads[x].start();
+ }
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ awaitBlocking(threads);
+
+ Thread[] extraneous = new Thread[extraneousCount];
+ for (int x = 0; x < extraneousCount; x++) {
+ extraneous[x] = new Thread(new ExtraneousRunnable(monitors[0]));
+ extraneous[x].start();
+ }
+ awaitBlocking(extraneous);
+ return threads;
+ }
+
+ void awaitBlocking(Thread[] threads) {
+ for (Thread thread : threads) {
+ while (thread.getState() != State.BLOCKED) {
+ try {
+ Thread.sleep(30);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ static final class DeadlockRunnable implements Runnable {
+
+ private final CountDownLatch latch;
+
+ private final Object first;
+
+ private final Object second;
+
+ /**
+ * @param latch
+ * @param first
+ * @param second
+ */
+ public DeadlockRunnable(CountDownLatch latch, Object first, Object second) {
+ this.latch = latch;
+ this.first = first;
+ this.second = second;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ synchronized (this.first) {
+ this.latch.countDown();
+ try {
+ this.latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ synchronized (this.second) {
+
+ }
+ }
+ }
+
+ }
+
+ static final class ExtraneousRunnable implements Runnable {
+
+ private final Object monitor;
+
+ /**
+ * @param monitor
+ */
+ public ExtraneousRunnable(Object monitor) {
+ this.monitor = monitor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ synchronized (this.monitor) {
+
+ }
+ }
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreatorMBean.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreatorMBean.java
new file mode 100644
index 00000000..9a5df938
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/concurrent/monitor/DeadlockCreatorMBean.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.concurrent.monitor;
+
+/**
+ */
+public interface DeadlockCreatorMBean {
+
+ Thread[] createDeadlock(int threadCount, int extraneousCount);
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepositoryTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepositoryTests.java
new file mode 100644
index 00000000..bd64eb7f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/EmptyRepositoryTests.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.repository.internal;
+
+import org.eclipse.virgo.kernel.services.repository.internal.EmptyRepository;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+
+/**
+ */
+public class EmptyRepositoryTests {
+
+ @Test
+ public void testContract() {
+ EmptyRepository repo = new EmptyRepository();
+ assertNotNull(repo.createQuery(null, null));
+ assertNotNull(repo.createQuery(null, null, null));
+ assertNotNull(repo.getName());
+ assertNull(repo.get(null, null, null));
+ assertNotNull(repo.createQuery(null, null).run());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBeanTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBeanTests.java
new file mode 100644
index 00000000..ffa7ecb9
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/repository/internal/RepositoryFactoryBeanTests.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.repository.internal;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.services.repository.internal.RepositoryFactoryBean;
+import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.Repository;
+import org.eclipse.virgo.repository.RepositoryFactory;
+
+
+/**
+ */
+public class RepositoryFactoryBeanTests {
+
+ private static MockEventLogger mockEventLogger = new MockEventLogger();
+
+ @Test
+ public void testCreateEmpty() throws Exception {
+ mockEventLogger.reinitialise();
+ Properties properties = new Properties();
+ RepositoryFactory factory = createMock(RepositoryFactory.class);
+ File work = new File("target");
+
+ RepositoryFactoryBean bean = new RepositoryFactoryBean(properties, mockEventLogger, factory, work, Collections.<ArtifactBridge>emptySet(), null);
+ Repository r = bean.getObject();
+ assertNotNull(r);
+ assertTrue("Event KS0001I was not logged.", mockEventLogger.isLogged("KS0001I"));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testCreate() throws Exception {
+ File work = new File("target");
+ mockEventLogger.reinitialise();
+
+ Properties properties = new Properties();
+ properties.put("bundles.type", "external");
+ properties.put("bundles.searchPattern", "target/*.jar");
+ properties.put("chain", "bundles");
+
+ RepositoryFactory factory = createMock(RepositoryFactory.class);
+ expect(factory.createRepository(isA(List.class))).andReturn(null);
+ replay(factory);
+
+ RepositoryFactoryBean bean = new RepositoryFactoryBean(properties, mockEventLogger, factory, work, Collections.<ArtifactBridge>emptySet(), null);
+ bean.getObject();
+
+ verify(factory);
+ assertFalse("Events were logged.", mockEventLogger.getCalled());
+ }
+
+ @Test
+ public void testBasicContract() {
+ mockEventLogger.reinitialise();
+ Properties properties = new Properties();
+ RepositoryFactory factory = createMock(RepositoryFactory.class);
+ File work = new File("target");
+
+ RepositoryFactoryBean bean = new RepositoryFactoryBean(properties, mockEventLogger, factory, work, Collections.<ArtifactBridge>emptySet(), null);
+ assertTrue(bean.isSingleton());
+ assertEquals(Repository.class, bean.getObjectType());
+ assertFalse("Events were logged.", mockEventLogger.getCalled());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/StandardWorkAreaTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/StandardWorkAreaTests.java
new file mode 100644
index 00000000..313f8081
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/StandardWorkAreaTests.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.work;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.services.work.StandardWorkArea;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.util.io.FileSystemUtils;
+import org.eclipse.virgo.util.io.PathReference;
+
+
+/**
+ */
+public class StandardWorkAreaTests {
+
+ private static final String WORK_DIR_NAME = "com.foo";
+
+
+ @Before
+ public void before() {
+ FileSystemUtils.deleteRecursively(new File("./target/work", WORK_DIR_NAME));
+ }
+
+ @Test
+ public void nonNullWorkDirectory() {
+
+ StubBundle bundle = new StubBundle(WORK_DIR_NAME, Version.emptyVersion);
+
+ StandardWorkArea manager = new StandardWorkArea(new File("./target/work"), bundle);
+ PathReference workDir = manager.getWorkDirectory();
+
+ assertNotNull(workDir);
+ assertTrue("work dir does not exist", workDir.exists());
+ assertTrue(workDir.isDirectory());
+
+ assertTrue(new File("./target/work", WORK_DIR_NAME + "_" + Version.emptyVersion).exists());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactoryTests.java b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactoryTests.java
new file mode 100644
index 00000000..f73155d9
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/java/org/eclipse/virgo/kernel/services/work/WorkAreaServiceFactoryTests.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * 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:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.services.work;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+
+import org.junit.Test;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.services.work.WorkArea;
+import org.eclipse.virgo.kernel.services.work.WorkAreaServiceFactory;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+
+/**
+ */
+public class WorkAreaServiceFactoryTests {
+
+ @Test
+ public void testCreate() {
+ File work = new File("target");
+ WorkAreaServiceFactory factory = new WorkAreaServiceFactory(work);
+
+ StubBundle bundle = new StubBundle("foo", new Version("1.0.0"));
+
+ WorkArea service = (WorkArea) factory.getService(bundle, null);
+ assertNotNull(service);
+ assertEquals(bundle, service.getOwner());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.services/src/test/resources/.gitignore b/org.eclipse.virgo.kernel.services/src/test/resources/.gitignore
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.services/src/test/resources/.gitignore

Back to the top