Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.virgo.kernel.core')
-rw-r--r--org.eclipse.virgo.kernel.core/.classpath50
-rw-r--r--org.eclipse.virgo.kernel.core/.project42
-rw-r--r--org.eclipse.virgo.kernel.core/.settings/com.springsource.server.ide.bundlor.core.prefs3
-rw-r--r--org.eclipse.virgo.kernel.core/.settings/org.eclipse.jdt.core.prefs70
-rw-r--r--org.eclipse.virgo.kernel.core/.settings/org.eclipse.wst.common.project.facet.core.xml4
-rw-r--r--org.eclipse.virgo.kernel.core/.springBeans20
-rw-r--r--org.eclipse.virgo.kernel.core/build.xml9
-rw-r--r--org.eclipse.virgo.kernel.core/findbugs-exclude.xml9
-rw-r--r--org.eclipse.virgo.kernel.core/ivy.xml37
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminConfigurationInfo.java63
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminDumpContributor.java101
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminExporter.java133
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInfo.java24
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInitialiser.java94
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisher.java82
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfiguration.java116
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSource.java60
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/PropertiesSource.java41
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSource.java113
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSource.java151
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReader.java85
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfParseException.java30
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSource.java167
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BlockingSignal.java65
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleStarter.java54
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleUtils.java54
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FailureSignalledException.java39
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FatalKernelException.java48
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/KernelException.java46
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Shutdown.java37
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Signal.java38
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/AsyncShutdownDecorator.java61
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/BundleStartTracker.java282
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivator.java238
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatus.java30
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatusMBean.java21
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/ShutdownManager.java136
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StandardBundleStarter.java82
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StartupTracker.java236
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitor.java304
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/StandardTicker.java255
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/Ticker.java52
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/diagnostics/KernelLogEvents.java65
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/Assert.java255
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/FatalServerException.java44
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/LogEventDelegate.java40
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/NonNull.java35
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/DumpCoordinator.aj74
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionState.java65
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcer.aj73
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/Scope.java61
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/ScopeFactory.java67
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/internal/StandardScopeFactory.java289
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/TracingService.java45
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/internal/Slf4jTracingService.java30
-rw-r--r--org.eclipse.virgo.kernel.core/src/main/resources/EventLogMessages.properties15
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfiguration.java58
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfigurationAdmin.java51
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisherTests.java140
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSourceTests.java48
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationTests.java61
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSourceTests.java45
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSourceTests.java126
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReaderTests.java37
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSourceTests.java84
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/BundleStartTrackerTests.java292
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivatorTests.java79
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/ShutdownManagerTests.java103
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/StartupTrackerTests.java192
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitorTests.java268
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/TickerTests.java44
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/AssertTests.java175
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionStateTests.java80
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcerTests.java74
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/java/test/AssertingService.java48
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_badprops/noprops.properties2
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise.config11
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise2.config11
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props1/dup.properties3
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props2/dup.properties6
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/one.properties1
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/two.properties1
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ovf/environment.xml26
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ovf/invalid.xml25
-rw-r--r--org.eclipse.virgo.kernel.core/src/test/resources/ovf/valid.xml28
-rw-r--r--org.eclipse.virgo.kernel.core/template.mf21
86 files changed, 6880 insertions, 0 deletions
diff --git a/org.eclipse.virgo.kernel.core/.classpath b/org.eclipse.virgo.kernel.core/.classpath
new file mode 100644
index 00000000..a545d0e8
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/.classpath
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java">
+ <attributes>
+ <attribute name="com.springsource.server.ide.jdt.core.test.classpathentry" value="false"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" path="src/main/resources">
+ <attributes>
+ <attribute name="com.springsource.server.ide.jdt.core.test.classpathentry" value="false"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+ <attributes>
+ <attribute name="com.springsource.server.ide.jdt.core.test.classpathentry" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry excluding="ConfigBundleTests/config_tests_badprops/|ConfigBundleTests/|customConfigDir/" kind="src" output="target/test-classes" path="src/test/resources">
+ <attributes>
+ <attribute name="com.springsource.server.ide.jdt.core.test.classpathentry" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-4.7.0.jar" sourcepath="/KERNEL_IVY_CACHE/org.junit/com.springsource.org.junit/4.7.0/com.springsource.org.junit-sources-4.7.0.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.osgi/org.eclipse.osgi/3.5.1.R35x_v20091005/org.eclipse.osgi-3.5.1.R35x_v20091005.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.osgi/org.eclipse.osgi/3.5.1.R35x_v20091005/org.eclipse.osgi-sources-3.5.1.R35x_v20091005.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.easymock/com.springsource.org.easymock/2.3.0/com.springsource.org.easymock-2.3.0.jar" sourcepath="/KERNEL_IVY_CACHE/org.easymock/com.springsource.org.easymock/2.3.0/com.springsource.org.easymock-sources-2.3.0.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.virgo.util/org.eclipse.virgo.util.io/2.1.0.D-20100420091708/org.eclipse.virgo.util.io-2.1.0.D-20100420091708.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.virgo.util/org.eclipse.virgo.util.io/2.1.0.D-20100420091708/org.eclipse.virgo.util.io-sources-2.1.0.D-20100420091708.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.springframework/org.springframework.beans/3.0.0.RELEASE/org.springframework.beans-3.0.0.RELEASE.jar" sourcepath="/KERNEL_IVY_CACHE/org.springframework/org.springframework.beans/3.0.0.RELEASE/org.springframework.beans-sources-3.0.0.RELEASE.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.apache.felix/org.apache.felix.configadmin/1.2.4/org.apache.felix.configadmin-1.2.4.jar" sourcepath="/KERNEL_IVY_CACHE/org.apache.felix/org.apache.felix.configadmin/1.2.4/org.apache.felix.configadmin-sources-1.2.4.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.springframework/org.springframework.core/3.0.0.RELEASE/org.springframework.core-3.0.0.RELEASE.jar" sourcepath="/KERNEL_IVY_CACHE/org.springframework/org.springframework.core/3.0.0.RELEASE/org.springframework.core-sources-3.0.0.RELEASE.jar"/>
+ <classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic/1.0.1.D-20100420092100/org.eclipse.virgo.medic-1.0.1.D-20100420092100.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic/1.0.0.CI-B20/org.eclipse.virgo.medic-sources-1.0.0.CI-B20.jar">
+ <attributes>
+ <attribute name="org.eclipse.ajdt.aspectpath" value="org.eclipse.ajdt.aspectpath"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic.core/1.0.1.D-20100420092100/org.eclipse.virgo.medic.core-1.0.1.D-20100420092100.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic.core/1.0.1.D-20100420092100/org.eclipse.virgo.medic.core-sources-1.0.1.D-20100420092100.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.slf4j/com.springsource.slf4j.nop/1.5.10/com.springsource.slf4j.nop-1.5.10.jar" sourcepath="/KERNEL_IVY_CACHE/org.slf4j/com.springsource.slf4j.nop/1.5.10/com.springsource.slf4j.nop-sources-1.5.10.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.virgo.teststubs/org.eclipse.virgo.teststubs.osgi/1.0.0.D-20100420091314/org.eclipse.virgo.teststubs.osgi-1.0.0.D-20100420091314.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.virgo.test/org.eclipse.virgo.teststubs.osgi/1.0.0.D-20100420091314/org.eclipse.virgo.teststubs.osgi-sources-1.0.0.D-20100420091314.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.slf4j/com.springsource.slf4j.api/1.5.10/com.springsource.slf4j.api-1.5.10.jar" sourcepath="/KERNEL_IVY_CACHE/org.slf4j/com.springsource.slf4j.api/1.5.10/com.springsource.slf4j.api-sources-1.5.10.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.virgo.util/org.eclipse.virgo.util.osgi/2.1.0.D-20100420091708/org.eclipse.virgo.util.osgi-2.1.0.D-20100420091708.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.virgo.util/org.eclipse.virgo.util.osgi/2.1.0.D-20100420091708/org.eclipse.virgo.util.osgi-sources-2.1.0.D-20100420091708.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.virgo.util/org.eclipse.virgo.util.common/2.1.0.D-20100420091708/org.eclipse.virgo.util.common-2.1.0.D-20100420091708.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.virgo.util/org.eclipse.virgo.util.common/2.1.0.D-20100420091708/org.eclipse.virgo.util.common-sources-2.1.0.D-20100420091708.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.apache.felix/org.apache.felix.eventadmin/1.0.0/org.apache.felix.eventadmin-1.0.0.jar" sourcepath="/KERNEL_IVY_CACHE/org.apache.felix/org.apache.felix.eventadmin/1.0.0/org.apache.felix.eventadmin-sources-1.0.0.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic.test/1.0.1.D-20100420092100/org.eclipse.virgo.medic.test-1.0.1.D-20100420092100.jar" sourcepath="/KERNEL_IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic.test/1.0.1.D-20100420092100/org.eclipse.virgo.medic.test-sources-1.0.1.D-20100420092100.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.springframework.osgi/org.springframework.osgi.extender/1.2.1/org.springframework.osgi.extender-1.2.1.jar" sourcepath="/KERNEL_IVY_CACHE/org.springframework.osgi/org.springframework.osgi.extender/1.2.1/org.springframework.osgi.extender-sources-1.2.1.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.springframework/org.springframework.context/3.0.0.RELEASE/org.springframework.context-3.0.0.RELEASE.jar" sourcepath="/KERNEL_IVY_CACHE/org.springframework/org.springframework.context/3.0.0.RELEASE/org.springframework.context-sources-3.0.0.RELEASE.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.springframework.osgi/org.springframework.osgi.core/1.2.1/org.springframework.osgi.core-1.2.1.jar" sourcepath="/KERNEL_IVY_CACHE/org.springframework.osgi/org.springframework.osgi.core/1.2.1/org.springframework.osgi.core-sources-1.2.1.jar"/>
+ <classpathentry kind="var" path="KERNEL_IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/org.eclipse.virgo.kernel.core/.project b/org.eclipse.virgo.kernel.core/.project
new file mode 100644
index 00000000..28d68953
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/.project
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.virgo.kernel.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.ajdt.core.ajbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.springsource.server.dev.eclipse.serverdevelopmentbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.springframework.ide.eclipse.core.springbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.springsource.server.ide.bundlor.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.ajdt.ui.ajnature</nature>
+ <nature>com.springsource.server.ide.facet.core.bundlenature</nature>
+ <nature>org.springframework.ide.eclipse.core.springnature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>com.springsource.server.dev.eclipse.serverdevelopmentnature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.virgo.kernel.core/.settings/com.springsource.server.ide.bundlor.core.prefs b/org.eclipse.virgo.kernel.core/.settings/com.springsource.server.ide.bundlor.core.prefs
new file mode 100644
index 00000000..ecb7aefe
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/.settings/com.springsource.server.ide.bundlor.core.prefs
@@ -0,0 +1,3 @@
+#Mon Jul 06 09:08:03 BST 2009
+com.springsource.server.ide.bundlor.core.template.properties.files=../build.versions
+eclipse.preferences.version=1
diff --git a/org.eclipse.virgo.kernel.core/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.virgo.kernel.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..aff8ee71
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,70 @@
+#Tue Feb 17 09:27:55 GMT 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/org.eclipse.virgo.kernel.core/.settings/org.eclipse.wst.common.project.facet.core.xml b/org.eclipse.virgo.kernel.core/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 00000000..801f856c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="com.springsource.server.bundle" version="1.0"/>
+</faceted-project>
diff --git a/org.eclipse.virgo.kernel.core/.springBeans b/org.eclipse.virgo.kernel.core/.springBeans
new file mode 100644
index 00000000..a5d06195
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/.springBeans
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beansProjectDescription>
+ <version>1</version>
+ <pluginVersion><![CDATA[2.2.4.RELEASE]]></pluginVersion>
+ <configSuffixes>
+ <configSuffix><![CDATA[xml]]></configSuffix>
+ </configSuffixes>
+ <enableImports><![CDATA[false]]></enableImports>
+ <configs>
+ </configs>
+ <configSets>
+ <configSet>
+ <name><![CDATA[org.eclipse.virgo.kernel.config]]></name>
+ <allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
+ <incomplete>false</incomplete>
+ <configs>
+ </configs>
+ </configSet>
+ </configSets>
+</beansProjectDescription>
diff --git a/org.eclipse.virgo.kernel.core/build.xml b/org.eclipse.virgo.kernel.core/build.xml
new file mode 100644
index 00000000..da67db0c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/build.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="org.eclipse.virgo.kernel.core">
+
+ <property name="findbugs.exclude.file" value="${basedir}/findbugs-exclude.xml"/>
+ <property file="${basedir}/../build.properties"/>
+ <property file="${basedir}/../build.versions"/>
+ <import file="${basedir}/../virgo-build/aspect/default.xml"/>
+
+</project>
diff --git a/org.eclipse.virgo.kernel.core/findbugs-exclude.xml b/org.eclipse.virgo.kernel.core/findbugs-exclude.xml
new file mode 100644
index 00000000..ceeb784b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/findbugs-exclude.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FindBugsFilter>
+ <!-- Exclusions -->
+ <Match>
+ <Bug pattern="DM_EXIT"/>
+ <Class name="org.eclipse.virgo.kernel.core.internal.ShutdownManager"/>
+ <Method name="immediateShutdown"/>
+ </Match>
+</FindBugsFilter>
diff --git a/org.eclipse.virgo.kernel.core/ivy.xml b/org.eclipse.virgo.kernel.core/ivy.xml
new file mode 100644
index 00000000..8b503b47
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/ivy.xml
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
+<ivy-module xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='http://incubator.apache.org/ivy/schemas/ivy.xsd' version='1.3'>
+
+ <info module='${ant.project.name}' organisation='org.eclipse.virgo.kernel'/>
+
+ <configurations>
+ <include file='${virgo.build.dir}/common/default-ivy-configurations.xml'/>
+ </configurations>
+
+ <publications>
+ <artifact name='${ant.project.name}'/>
+ <artifact name='${ant.project.name}-sources' ext='jar' type='src'/>
+ </publications>
+
+ <dependencies>
+ <dependency name='com.springsource.org.junit' rev='${org.junit}' org='org.junit' conf='test->runtime'/>
+ <dependency name='com.springsource.org.easymock' rev='${org.easymock}' org='org.easymock' conf='test->runtime'/>
+ <dependency name='org.eclipse.virgo.teststubs.osgi' rev='${org.eclipse.virgo.teststubs}' org='org.eclipse.virgo.teststubs' conf='test->runtime'/>
+ <dependency name='org.eclipse.osgi' rev='${org.eclipse.osgi}' org='org.eclipse.osgi' conf='compile->runtime'/>
+ <dependency name='org.apache.felix.configadmin' rev='${org.apache.felix}' org='org.apache.felix' conf='compile->runtime'/>
+ <dependency name='org.eclipse.virgo.util.io' rev='${org.eclipse.virgo.util}' org='org.eclipse.virgo.util' conf='compile->compile'/>
+ <dependency name='org.eclipse.virgo.util.jmx' rev='${org.eclipse.virgo.util}' org='org.eclipse.virgo.util' conf='aspects->runtime'/>
+ <dependency name='org.eclipse.virgo.util.osgi' rev='${org.eclipse.virgo.util}' org='org.eclipse.virgo.util' conf='compile->compile'/>
+ <dependency name='com.springsource.slf4j.api' rev='${org.slf4j}' org='org.slf4j' conf='compile->runtime'/>
+ <dependency name='com.springsource.slf4j.nop' rev='${org.slf4j}' org='org.slf4j' conf='test->runtime'/>
+ <dependency name='org.eclipse.virgo.medic' rev='${org.eclipse.virgo.medic}' org='org.eclipse.virgo.medic' conf='aspects, compile->runtime'/>
+ <dependency name='org.eclipse.virgo.medic.core' rev='${org.eclipse.virgo.medic}' org='org.eclipse.virgo.medic' conf='runtime->runtime'/>
+ <dependency name='org.eclipse.virgo.medic.test' rev='${org.eclipse.virgo.medic}' org='org.eclipse.virgo.medic' conf='test->runtime'/>
+ <dependency name='org.apache.felix.eventadmin' rev='${org.apache.felix.eventadmin}' conf='compile->compile' org='org.apache.felix'/>
+ <dependency org="org.springframework.osgi" name="org.springframework.osgi.extender" rev="${org.springframework.osgi}" conf="compile->compile"/>
+ <dependency org="org.springframework.osgi" name="org.springframework.osgi.core" rev="${org.springframework.osgi}" conf="compile->compile"/>
+ <override org="org.springframework" rev="${org.springframework}"/>
+ <override org="org.eclipse.virgo.util" rev="${org.eclipse.virgo.util}"/>
+ </dependencies>
+
+</ivy-module>
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminConfigurationInfo.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminConfigurationInfo.java
new file mode 100644
index 00000000..e15805d2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminConfigurationInfo.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class ConfigurationAdminConfigurationInfo implements ConfigurationInfo {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final ConfigurationAdmin configurationAdmin;
+
+ private final String pid;
+
+ public ConfigurationAdminConfigurationInfo(ConfigurationAdmin configurationAdmin, String pid) {
+ this.configurationAdmin = configurationAdmin;
+ this.pid = pid;
+ }
+
+ public String getPid() {
+ return this.pid;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Map<String, String> getProperties() {
+ try {
+ Configuration configuration = configurationAdmin.getConfiguration(this.pid, null);
+ Dictionary<String, String> dictionary = configuration.getProperties();
+
+ Map<String, String> properties = new HashMap<String, String>(dictionary.size());
+ Enumeration<String> keys = dictionary.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ String value = dictionary.get(key);
+ properties.put(key, value);
+ }
+ return properties;
+ } catch (IOException e) {
+ logger.warn("Unable to get configuration for {}", this.pid);
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminDumpContributor.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminDumpContributor.java
new file mode 100644
index 00000000..8b85a3fa
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminDumpContributor.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.config.internal;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.virgo.medic.dump.Dump;
+import org.eclipse.virgo.medic.dump.DumpContributionFailedException;
+import org.eclipse.virgo.medic.dump.DumpContributor;
+
+public class ConfigurationAdminDumpContributor implements DumpContributor {
+
+ private static final String PROPERTY_PATTERN = "%s:\t%s\n";
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final ConfigurationAdmin configurationAdmin;
+
+ public ConfigurationAdminDumpContributor(ConfigurationAdmin configurationAdmin) {
+ this.configurationAdmin = configurationAdmin;
+ }
+
+ public void contribute(Dump dump) throws DumpContributionFailedException {
+ StringBuilder sb = new StringBuilder();
+
+ try {
+ for (Configuration configuration : configurationAdmin.listConfigurations(null)) {
+ appendHeader(sb, configuration.getPid());
+ appendProperties(sb, configuration.getProperties());
+ appendFooter(sb);
+ }
+ } catch (Exception e) {
+ logger.warn("Could not enumerate existing configurations");
+ }
+
+ Writer out = null;
+ try {
+ out = dump.createFileWriter("configurationAdmin.properties");
+ out.write(sb.toString());
+ } catch (IOException e) {
+ logger.warn("Could not write configurationAdmin dump");
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // Nothing to do
+ }
+ }
+ }
+ }
+
+ public String getName() {
+ return "configurationAdmin";
+ }
+
+ private void appendHeader(StringBuilder sb, String pid) {
+ for (int i = 0; i < pid.length() + 4; i++) {
+ sb.append("#");
+ }
+ sb.append("\n# ").append(pid).append(" #\n");
+ for (int i = 0; i < pid.length() + 4; i++) {
+ sb.append("#");
+ }
+ sb.append("\n\n");
+ }
+
+ private void appendProperties(StringBuilder sb, Dictionary properties) {
+ Enumeration keys = properties.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ appendProperty(sb, key, properties.get(key));
+ }
+ }
+
+ private void appendProperty(StringBuilder sb, Object key, Object value) {
+ sb.append(String.format(PROPERTY_PATTERN, key, value));
+ }
+
+ private void appendFooter(StringBuilder sb) {
+ sb.append("\n\n");
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminExporter.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminExporter.java
new file mode 100644
index 00000000..c2010598
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationAdminExporter.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+// TODO Remove alien calls made while holding this.monitor
+public class ConfigurationAdminExporter implements ConfigurationListener {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private static final String OBJECT_NAME_PATTERN = "%s:type=Configuration,name=%s";
+
+ private final Map<String, ObjectInstance> configurationInfos = new HashMap<String, ObjectInstance>();
+
+ private final Object monitor = new Object();
+
+ private final String managementDomain;
+
+ private final ConfigurationAdmin configurationAdmin;
+
+ public ConfigurationAdminExporter(String managementDomain, ConfigurationAdmin configurationAdmin) {
+ this.managementDomain = managementDomain;
+ this.configurationAdmin = configurationAdmin;
+ }
+
+ public void init() {
+ synchronized (this.monitor) {
+ try {
+ for (Configuration configuration : configurationAdmin.listConfigurations(null)) {
+ exportConfiguration(configuration.getPid());
+ }
+ } catch (Exception e) {
+ logger.warn("Could not enumerate existing configurations");
+ }
+ }
+ }
+
+ public void configurationEvent(ConfigurationEvent configurationEvent) {
+ String pid = configurationEvent.getPid();
+ if (ConfigurationEvent.CM_UPDATED == configurationEvent.getType()) {
+ exportConfiguration(pid);
+ } else if (ConfigurationEvent.CM_DELETED == configurationEvent.getType()) {
+ unexportConfiguration(pid);
+ }
+ }
+
+ private ObjectName getObjectName(String pid) throws MalformedObjectNameException, NullPointerException {
+ return new ObjectName(String.format(OBJECT_NAME_PATTERN, this.managementDomain, pid));
+ }
+
+ private void exportConfiguration(String pid) {
+ synchronized (this.monitor) {
+ if (!configurationInfos.containsKey(pid)) {
+ try {
+ ConfigurationInfo configurationInfo = new ConfigurationAdminConfigurationInfo(this.configurationAdmin, pid);
+ ObjectInstance objectInstance = server.registerMBean(configurationInfo, getObjectName(pid));
+ this.configurationInfos.put(pid, objectInstance);
+ } catch (JMException e) {
+ logger.warn("Unable to register MBean for configuration '{}'", pid);
+ }
+ }
+ }
+ }
+
+ private void unexportConfiguration(String pid) {
+ ObjectName objectName;
+
+ synchronized (this.monitor) {
+ objectName = configurationInfos.remove(pid).getObjectName();
+ }
+
+ try {
+ this.server.unregisterMBean(objectName);
+ } catch (JMException e) {
+ this.logger.warn("Unable to unregister MBean for configuration '{}'", pid);
+ }
+ }
+
+ /**
+ *
+ */
+ public void stop() {
+ List<ObjectName> objectNames = new ArrayList<ObjectName>();
+
+ synchronized (this.monitor) {
+ Set<Entry<String, ObjectInstance>> entries = this.configurationInfos.entrySet();
+ for (Entry<String, ObjectInstance> entry : entries) {
+ objectNames.add(entry.getValue().getObjectName());
+ }
+ this.configurationInfos.clear();
+ }
+
+ for (ObjectName objectName : objectNames) {
+ try {
+ this.server.unregisterMBean(objectName);
+ } catch (JMException jme) {
+ logger.warn("Unable to unregister MBean '{}' during stop", objectName);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInfo.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInfo.java
new file mode 100644
index 00000000..142f4576
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInfo.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.config.internal;
+
+import java.util.Map;
+
+import javax.management.MXBean;
+
+@MXBean
+public interface ConfigurationInfo {
+
+ String getPid();
+
+ Map<String, String> getProperties();
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInitialiser.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInitialiser.java
new file mode 100644
index 00000000..19ee78ab
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationInitialiser.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import java.io.IOException;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationListener;
+
+import org.eclipse.virgo.kernel.config.internal.commandline.CommandLinePropertiesSource;
+import org.eclipse.virgo.kernel.config.internal.ovf.OvfPropertiesSource;
+import org.eclipse.virgo.medic.dump.DumpContributor;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.util.osgi.ServiceRegistrationTracker;
+
+/**
+ * ConfigurationInitialiser
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * threadsafe
+ *
+ */
+public final class ConfigurationInitialiser {
+
+ private final ServiceRegistrationTracker tracker = new ServiceRegistrationTracker();
+
+ private volatile ConfigurationAdminExporter configAdminExporter;
+
+ public KernelConfiguration start(BundleContext context, EventLogger eventLogger) throws IOException {
+
+ ServiceReference configurationAdminReference = context.getServiceReference(ConfigurationAdmin.class.getName());
+
+ ConfigurationAdmin configAdmin = null;
+
+ if (configurationAdminReference != null) {
+ configAdmin = (ConfigurationAdmin) context.getService(configurationAdminReference);
+ }
+
+ if (configAdmin == null) {
+ throw new IllegalStateException("ConfigurationAdmin service missing");
+ }
+ KernelConfiguration configuration = new KernelConfiguration(context);
+
+ publishConfiguration(context, eventLogger, configuration, configAdmin);
+ this.configAdminExporter = initializeConfigAdminExporter(context, configuration, configAdmin);
+ initializeDumpContributor(context, configAdmin);
+ return configuration;
+
+ }
+
+ private void publishConfiguration(BundleContext context, EventLogger eventLogger, KernelConfiguration configuration,
+ ConfigurationAdmin configAdmin) throws IOException {
+ PropertiesSource[] sources = new PropertiesSource[] { new UserConfigurationPropertiesSource(configuration.getConfigDirectories()),
+ new OvfPropertiesSource(context, eventLogger), new KernelConfigurationPropertiesSource(configuration),
+ new CommandLinePropertiesSource(context, eventLogger) };
+ ConfigurationPublisher configPublisher = new ConfigurationPublisher(configAdmin, sources);
+ configPublisher.publishConfigurations();
+ }
+
+ private void initializeDumpContributor(BundleContext context, ConfigurationAdmin configAdmin) {
+ ConfigurationAdminDumpContributor dumpContributor = new ConfigurationAdminDumpContributor(configAdmin);
+ this.tracker.track(context.registerService(DumpContributor.class.getName(), dumpContributor, null));
+ }
+
+ private ConfigurationAdminExporter initializeConfigAdminExporter(BundleContext context, KernelConfiguration configuration, ConfigurationAdmin configAdmin) {
+ ConfigurationAdminExporter exporter = new ConfigurationAdminExporter(configuration.getDomain(), configAdmin);
+ this.tracker.track(context.registerService(ConfigurationListener.class.getName(), exporter, null));
+ exporter.init();
+ return exporter;
+ }
+
+ public void stop() {
+ this.tracker.unregisterAll();
+
+ ConfigurationAdminExporter local = this.configAdminExporter;
+
+ if (local != null) {
+ this.configAdminExporter = null;
+ local.stop();
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisher.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisher.java
new file mode 100644
index 00000000..c51ebeaf
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisher.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Map.Entry;
+
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import org.eclipse.virgo.kernel.serviceability.NonNull;
+import org.eclipse.virgo.util.common.IterableEnumeration;
+
+/**
+ * <code>ConfigurationPublisher</code>, publishes kernel configuration to {@link ConfigurationAdmin}.
+ * <p/>
+ * Properties files in {@link KernelConfiguration#getConfigDirectories() config directories} are read in and applied to
+ * {@link Configuration Configurations} owned by <code>ConfigurationAdmin</code>. A file called
+ * <code><i>name</i>.properties</code> results in a <Code>Configuration</code> with the service pid
+ * <code><i>name</i></code>.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ *
+ */
+final class ConfigurationPublisher {
+
+ private final ConfigurationAdmin configAdmin;
+
+ private final PropertiesSource[] sources;
+
+ ConfigurationPublisher(ConfigurationAdmin configAdmin, PropertiesSource... sources) {
+ this.configAdmin = configAdmin;
+ this.sources = (sources == null ? new PropertiesSource[0] : sources);
+ }
+
+ void publishConfigurations() throws IOException {
+ for (PropertiesSource source : this.sources) {
+ Map<String, Properties> configurationProperties = source.getConfigurationProperties();
+ if (configurationProperties != null) {
+ for (Entry<String, Properties> entry : configurationProperties.entrySet()) {
+ populateConfigurationWithProperties(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private void populateConfigurationWithProperties(@NonNull String pid, @NonNull Properties properties) throws IOException {
+ Configuration config = this.configAdmin.getConfiguration(pid, null);
+
+ Dictionary configProperties = config.getProperties();
+ if (configProperties == null) {
+ configProperties = new Hashtable();
+ }
+
+ for (Object key : new IterableEnumeration(properties.keys())) {
+ Object value = properties.get(key);
+ configProperties.put(key, value);
+ }
+
+ config.update(configProperties);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfiguration.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfiguration.java
new file mode 100644
index 00000000..88fc00f5
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfiguration.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+
+public final class KernelConfiguration {
+
+ static final String PROPERTY_KERNEL_CONFIG = "org.eclipse.virgo.kernel.config";
+
+ static final String PROPERTY_KERNEL_HOME = "org.eclipse.virgo.kernel.home";
+
+ static final String PROPERTY_KERNEL_DOMAIN = "org.eclipse.virgo.kernel.domain";
+
+ private static final String DEFAULT_WORK_DIRECTORY_NAME = "work";
+
+ private static final String DEFAULT_CONFIG_DIRECTORY_NAME = "config";
+
+ private static final String DEFAULT_KERNEL_DOMAIN = "org.eclipse.virgo.kernel";
+
+ private final File homeDirectory;
+
+ private final File[] configDirectories;
+
+ private final File workDirectory;
+
+ private final String domain;
+
+ public KernelConfiguration(BundleContext context) {
+ this.homeDirectory = readHomeDirectory(context);
+ this.configDirectories = readConfigDirectories(context);
+ this.workDirectory = new File(this.homeDirectory, DEFAULT_WORK_DIRECTORY_NAME);
+ this.domain = readDomain(context);
+ }
+
+ public File getHomeDirectory() {
+ return homeDirectory;
+ }
+
+ public File[] getConfigDirectories() {
+ return configDirectories.clone();
+ }
+
+ public File getWorkDirectory() {
+ return workDirectory;
+ }
+
+ public String getDomain() {
+ return domain;
+ }
+
+ private static File readHomeDirectory(BundleContext context) {
+ String kernelHomeProperty = readFrameworkProperty(PROPERTY_KERNEL_HOME, context);
+ if (!hasText(kernelHomeProperty)) {
+ throw new IllegalStateException(PROPERTY_KERNEL_HOME + " property must be specified, and must not be empty");
+ } else {
+ return new File(kernelHomeProperty);
+ }
+ }
+
+ private static File[] readConfigDirectories(BundleContext context) {
+ String kernelConfigProperty = readFrameworkProperty(PROPERTY_KERNEL_CONFIG, context);
+ List<File> configDirectories = new ArrayList<File>();
+
+ if (hasText(kernelConfigProperty)) {
+ parseKernelConfigProperty(kernelConfigProperty, configDirectories);
+ }
+
+ if (configDirectories.isEmpty()) {
+ configDirectories.add(new File(DEFAULT_CONFIG_DIRECTORY_NAME));
+ }
+
+ return configDirectories.toArray(new File[configDirectories.size()]);
+ }
+
+ private static void parseKernelConfigProperty(String kernelConfigProperty, List<File> configDirectories) {
+ String[] components = kernelConfigProperty.split(",");
+ for (String component : components) {
+ File configDir = new File(component.trim());
+ if (!configDir.isAbsolute()) {
+ configDir = new File(component.trim());
+ }
+ configDirectories.add(configDir);
+ }
+ }
+
+ private static String readDomain(BundleContext context) {
+ String kernelDomainProperty = readFrameworkProperty(PROPERTY_KERNEL_DOMAIN, context);
+ if (!hasText(kernelDomainProperty)) {
+ kernelDomainProperty = DEFAULT_KERNEL_DOMAIN;
+ }
+ return kernelDomainProperty;
+ }
+
+ private static String readFrameworkProperty(String propertyKey, BundleContext context) {
+ return context.getProperty(propertyKey);
+ }
+
+ private static boolean hasText(String string) {
+ return (string != null && !string.trim().isEmpty());
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSource.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSource.java
new file mode 100644
index 00000000..56433920
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSource.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.config.internal;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Implementation of {@link PropertiesSource} that exposes the {@link KernelConfiguration} as {@link Properties}.
+ * <p />
+ * Ideally the properties exposed from instances of this object should not be overridden by properties from another
+ * source.
+ * <p/>
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+final class KernelConfigurationPropertiesSource implements PropertiesSource {
+
+ static final String PROPERTY_WORK_DIRECTORY = "work.directory";
+
+ static final String PROPERTY_HOME_DIRECTORY = "home.directory";
+
+ static final String PROPERTY_DOMAIN = "domain";
+
+ static final String KERNEL_CONFIGURATION_PID = "org.eclipse.virgo.kernel";
+
+ private final KernelConfiguration kernelConfiguration;
+
+ public KernelConfigurationPropertiesSource(KernelConfiguration kernelConfiguration) {
+ this.kernelConfiguration = kernelConfiguration;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Properties> getConfigurationProperties() {
+ return Collections.singletonMap(KERNEL_CONFIGURATION_PID, createProperties());
+ }
+
+ private Properties createProperties() {
+ Properties properties = new Properties();
+ properties.put(PROPERTY_DOMAIN, this.kernelConfiguration.getDomain());
+ properties.put(PROPERTY_HOME_DIRECTORY, this.kernelConfiguration.getHomeDirectory().getAbsolutePath());
+ properties.put(PROPERTY_WORK_DIRECTORY, this.kernelConfiguration.getWorkDirectory().getAbsolutePath());
+ return properties;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/PropertiesSource.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/PropertiesSource.java
new file mode 100644
index 00000000..5776157e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/PropertiesSource.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.config.internal;
+
+import java.util.Map;
+import java.util.Properties;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Represents a source for configuration properties. These configuration properties will be exported to
+ * {@link ConfigurationAdmin} under the kernel PID.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations must be threadsafe.
+ *
+ */
+public interface PropertiesSource {
+
+ /**
+ * Gets all the configuration properties from this source.
+ * <p/>
+ * Each entry in the map represents one configuration. The entry key is the PID of the configuration, and the entry
+ * value is the properties to be exposed under that PID.
+ *
+ * @return all configuration properties from this source.
+ */
+ Map<String, Properties> getConfigurationProperties();
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSource.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSource.java
new file mode 100644
index 00000000..7a6a0abe
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSource.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+import org.eclipse.virgo.util.io.IOUtils;
+
+/**
+ * Implementation of {@link PropertiesSource} that loads all the configuration supplied by the kernel user.
+ *
+ * <p/>
+ *
+ * User configuration is loaded from all properties files found in the directories listed in the
+ * {@link KernelConfiguration#getConfigDirectories() configuration directories}.
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+final class UserConfigurationPropertiesSource implements PropertiesSource {
+
+ private static final String PROPERTIES_FILE_SUFFIX = ".properties";
+
+ private static final FilenameFilter PROPERTIES_FILENAME_FILTER = new FilenameFilter() {
+
+ public boolean accept(File dir, String name) {
+ return name.endsWith(PROPERTIES_FILE_SUFFIX);
+ }
+ };
+
+ private final File[] kernelConfigDirectories;
+
+ /**
+ * Creates a new <code>UserConfigurationPropertiesSource</code> that loads config files from the supplied user
+ * config directories.
+ *
+ * @param kernelConfigDirectories the directories containing the users kernel config files.
+ */
+ public UserConfigurationPropertiesSource(File[] kernelConfigDirectories) {
+ this.kernelConfigDirectories = kernelConfigDirectories;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Properties> getConfigurationProperties() {
+ Map<String, Properties> result = new TreeMap<String, Properties>();
+ for (File dir : this.kernelConfigDirectories) {
+ File[] configFiles = getPropertiesFiles(dir);
+ for (File file : configFiles) {
+ String pid = createPid(file);
+ Properties properties = readPropertiesFromFile(file);
+ // Last pid encountered wins; no merging is performed
+ result.put(pid, properties);
+ }
+ }
+ return result;
+ }
+
+ private static File[] getPropertiesFiles(File directory) {
+ File[] files = directory.listFiles(PROPERTIES_FILENAME_FILTER);
+ if (files == null) {
+ return new File[0];
+ }
+ return files;
+ }
+
+ private Properties readPropertiesFromFile(File file) {
+ if (!file.exists()) {
+ return null;
+ }
+ Properties props = new Properties();
+ InputStream is = null;
+ try {
+ is = new BufferedInputStream(new FileInputStream(file));
+ props.load(is);
+ } catch (IOException ioe) {
+ // silently ignored
+ return null;
+ } finally {
+ IOUtils.closeQuietly(is);
+ }
+ return props;
+ }
+
+ private static String createPid(final File file) {
+ return trimExtension(file.getName());
+ }
+
+ private static String trimExtension(final String name) {
+ int lpDot = name.lastIndexOf('.');
+ return lpDot == -1 ? name : name.substring(0, lpDot);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSource.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSource.java
new file mode 100644
index 00000000..eadcec98
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSource.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.config.internal.commandline;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.osgi.framework.BundleContext;
+
+
+import org.eclipse.virgo.kernel.config.internal.PropertiesSource;
+import org.eclipse.virgo.kernel.diagnostics.KernelLogEvents;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+
+public final class CommandLinePropertiesSource implements PropertiesSource {
+
+ private static final String PROPERTY_USERREGION_COMMANDLINE_ARTIFACTS = "commandLineArtifacts";
+
+ private static final String PROPERTY_UNRECOGNIZED_LAUNCHER_ARGUMENTS = "org.eclipse.virgo.osgi.launcher.unrecognizedArguments";
+
+ private static final String COMMAND_PREFIX = "-";
+
+ private static final String COMMAND_PLAN = "plan";
+
+ private static final String PID_KERNEL_REGION = "org.eclipse.virgo.kernel.userregion";
+
+ private static final String TEMPLATE_VERSIONED_PLAN_REPOSITORY_URI = "repository:plan/%s/%s";
+
+ private static final String TEMPLATE_UNVERSIONED_PLAN_REPOSITORY_URI = "repository:plan/%s";
+
+ private final String unrecognizedArguments;
+
+ private final EventLogger eventLogger;
+
+ public CommandLinePropertiesSource(BundleContext bundleContext, EventLogger eventLogger) {
+ this.unrecognizedArguments = bundleContext.getProperty(PROPERTY_UNRECOGNIZED_LAUNCHER_ARGUMENTS);
+ this.eventLogger = eventLogger;
+ }
+
+ public Map<String, Properties> getConfigurationProperties() {
+
+ Map<String, Properties> configuration = new HashMap<String, Properties>();
+
+ if (this.unrecognizedArguments != null) {
+ String[] components = this.unrecognizedArguments.split(",");
+
+ List<String> arguments = null;
+ String command = null;
+
+ for (int i = 0; i < components.length; i++) {
+ if (components[i].startsWith(COMMAND_PREFIX)) {
+ if (command != null) {
+ processCommand(command, arguments, configuration);
+ }
+ command = components[i].substring(COMMAND_PREFIX.length());
+ arguments = new ArrayList<String>();
+ } else if (arguments != null) {
+ arguments.add(components[i]);
+ }
+ }
+
+ if (command != null) {
+ processCommand(command, arguments, configuration);
+ }
+ }
+
+ applyDefaults(configuration);
+
+ return configuration;
+ }
+
+ private void applyDefaults(Map<String, Properties> configuration) {
+ Properties properties = getProperties(PID_KERNEL_REGION, configuration);
+ String userArtifacts = properties.getProperty(PROPERTY_USERREGION_COMMANDLINE_ARTIFACTS);
+ if (userArtifacts == null) {
+ properties.put(PROPERTY_USERREGION_COMMANDLINE_ARTIFACTS, "");
+ }
+ }
+
+ private void processCommand(String command, List<String> arguments, Map<String, Properties> configuration) {
+ if (COMMAND_PLAN.equals(command)) {
+ processPlanCommand(arguments, configuration);
+ }
+ }
+
+ private void processPlanCommand(List<String> arguments, Map<String, Properties> configuration) {
+ String repositoryUri = null;
+
+ if (arguments.size() == 1) {
+ repositoryUri = String.format(TEMPLATE_UNVERSIONED_PLAN_REPOSITORY_URI, arguments.get(0));
+ } else if (arguments.size() == 2) {
+ repositoryUri = String.format(TEMPLATE_VERSIONED_PLAN_REPOSITORY_URI, arguments.get(0), arguments.get(1));
+ } else {
+ this.eventLogger.log(KernelLogEvents.KERNEL_PLAN_ARGUMENTS_INCORRECT, arguments.size(), formatArgumentList(arguments));
+ }
+
+ if (repositoryUri != null) {
+ Properties properties = getProperties(PID_KERNEL_REGION, configuration);
+ appendProperty(PROPERTY_USERREGION_COMMANDLINE_ARTIFACTS, repositoryUri, properties);
+ }
+ }
+
+ private String formatArgumentList(List<String> arguments) {
+ if (arguments.size() == 0) {
+ return "";
+ }
+
+ StringBuilder argumentsBuilder = new StringBuilder();
+
+ for (int i = 0; i < arguments.size(); i++) {
+ argumentsBuilder.append(arguments.get(i));
+ if ((i + 1) < arguments.size()) {
+ argumentsBuilder.append(", ");
+ }
+ }
+
+ return argumentsBuilder.toString();
+ }
+
+ private Properties getProperties(String pid, Map<String, Properties> configuration) {
+ Properties properties = configuration.get(pid);
+ if (properties == null) {
+ properties = new Properties();
+ configuration.put(pid, properties);
+ }
+ return properties;
+ }
+
+ private void appendProperty(String key, String value, Properties properties) {
+ String property = properties.getProperty(key);
+ if (property != null) {
+ property = property + "," + value;
+ } else {
+ property = value;
+ }
+ properties.put(key, property);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReader.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReader.java
new file mode 100644
index 00000000..2457605a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReader.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.config.internal.ovf;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Simple reader class that reads all properties contained in the <code>PropertySection</code> of an OVF environment
+ * document.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe
+ *
+ */
+final class OvfEnvironmentPropertiesReader {
+
+ private static final String ATTRIBUTE_VALUE = "value";
+
+ private static final String ATTRIBUTE_KEY = "key";
+
+ private static final String ELEMENT_PROPERTY = "Property";
+
+ private static final String NAMESPACE_ENVIRONMENT = "http://schemas.dmtf.org/ovf/environment/1";
+
+ /**
+ * Reads all the properties from the OVF whose content is accessible using the supplied {@link Reader}.
+ *
+ * @param documentReader the reader for the OVF document.
+ * @return the properties contained in the OVF document.
+ */
+ public Properties readProperties(Reader documentReader) {
+ Properties result = new Properties();
+ Document doc = readDocument(documentReader);
+ parseProperties(doc, result);
+ return result;
+ }
+
+ private void parseProperties(Document doc, Properties result) {
+ NodeList propertyElements = doc.getElementsByTagNameNS(NAMESPACE_ENVIRONMENT, ELEMENT_PROPERTY);
+ for (int x = 0; x < propertyElements.getLength(); x++) {
+ Element propertyElement = (Element) propertyElements.item(x);
+ String key = propertyElement.getAttributeNS(NAMESPACE_ENVIRONMENT, ATTRIBUTE_KEY);
+ String value = propertyElement.getAttributeNS(NAMESPACE_ENVIRONMENT, ATTRIBUTE_VALUE);
+ result.setProperty(key, value);
+ }
+ }
+
+ private Document readDocument(Reader documentReader) {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return builder.parse(new InputSource(documentReader));
+ } catch (ParserConfigurationException e) {
+ throw new OvfParseException("Error configuring XML parser.", e);
+ } catch (SAXException e) {
+ throw new OvfParseException("Error parsing OVF XML document.", e);
+ } catch (IOException e) {
+ throw new OvfParseException("Error reading OVF XML document.", e);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfParseException.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfParseException.java
new file mode 100644
index 00000000..19569399
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfParseException.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.config.internal.ovf;
+
+/**
+ * Indicates an exception when parsing an OVF document.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+final class OvfParseException extends RuntimeException {
+
+ private static final long serialVersionUID = 8134710938140233L;
+
+ public OvfParseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSource.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSource.java
new file mode 100644
index 00000000..304d2d57
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSource.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * 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.config.internal.ovf;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+
+
+import org.eclipse.virgo.kernel.config.internal.PropertiesSource;
+import org.eclipse.virgo.kernel.diagnostics.KernelLogEvents;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.util.io.IOUtils;
+
+/**
+ * Implementation of {@link PropertiesSource} that reads properties from an OVF document.
+ * <p />
+ * The path to the OVF document is specified using the <code>org.eclipse.virgo.kernel.config.ovf</code> framework
+ * property.
+ * <p/>
+ * In order for a property in the OVF document to be exported to OVF its key should have the following format: <br/>
+ *
+ * <pre>
+ * cm:&lt;pid&gt;:&lt;property-name&gt;
+ * </pre>
+ *
+ * Any property keys not starting with the <code>cm:</code> prefix are not exported to config admin. Further, any
+ * <code>cm:</code> properties not having both and PID and and name portion will cause an exception.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public final class OvfPropertiesSource implements PropertiesSource {
+
+ static final String FRAMEWORK_PROPERTY_OVF = "org.eclipse.virgo.kernel.config.ovf";
+
+ private static final String PROPERTY_PREFIX = "cm:";
+
+ private static final String PROPERTY_DELIMITER = ":";
+
+ private final BundleContext bundleContext;
+
+ private final EventLogger eventLogger;
+
+ public OvfPropertiesSource(BundleContext bundleContext, EventLogger eventLogger) {
+ this.bundleContext = bundleContext;
+ this.eventLogger = eventLogger;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Properties> getConfigurationProperties() {
+ Properties sourceProperties = readSourceProperties();
+ if (sourceProperties != null) {
+ return translateProperties(sourceProperties);
+ } else {
+ return null;
+ }
+ }
+
+ private Map<String, Properties> translateProperties(Properties sourceProperties) {
+ Map<String, Properties> result = new HashMap<String, Properties>();
+ Set<String> propertyNames = sourceProperties.stringPropertyNames();
+ for (String propertyName : propertyNames) {
+ ConfigAdminProperty prop = tryReadConfigAdminProperty(propertyName);
+ if(prop != null) {
+ Properties p = result.get(prop.pid);
+ if(p == null) {
+ p = new Properties();
+ result.put(prop.pid, p);
+ }
+ p.setProperty(prop.key, sourceProperties.getProperty(propertyName));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to convert a property name into a valid configuration admin property based on the format laid out in
+ * {@link OvfPropertiesSource}.
+ *
+ * @param propertyName the unparsed property name
+ * @return a {@link ConfigAdminProperty} or <code>null</code> if the property is not prefixed with <code>cm:</code>
+ */
+ private ConfigAdminProperty tryReadConfigAdminProperty(String propertyName) {
+ ConfigAdminProperty result = null;
+ if(propertyName.startsWith(PROPERTY_PREFIX)) {
+ String parsed = propertyName.substring(PROPERTY_PREFIX.length());
+ String[] components = parsed.split(PROPERTY_DELIMITER);
+ if(components.length != 2) {
+ throw new IllegalArgumentException("Invalid configuration admin property '" + propertyName + "' found in OVF.");
+ } else {
+ result = new ConfigAdminProperty();
+ result.pid = components[0];
+ result.key = components[1];
+ }
+ }
+ return result;
+ }
+
+ private Properties readSourceProperties() {
+ Properties result = null;
+ File ovfFile = determineOvfFile();
+ if (ovfFile != null) {
+ if (!ovfFile.exists()) {
+ this.eventLogger.log(KernelLogEvents.OVF_CONFIGURATION_FILE_DOES_NOT_EXIST, ovfFile.getAbsolutePath());
+ } else {
+ result = readOvfFile(ovfFile);
+ }
+
+ }
+ return result;
+ }
+
+ private File determineOvfFile() {
+ File result = null;
+
+ String path = this.bundleContext.getProperty(FRAMEWORK_PROPERTY_OVF);
+ if (path != null) {
+ result = new File(path);
+ }
+
+ return result;
+ }
+
+ private Properties readOvfFile(File ovfFile) {
+ Properties result = null;
+ Reader reader = null;
+ try {
+ reader = new FileReader(ovfFile);
+ OvfEnvironmentPropertiesReader ovfReader = new OvfEnvironmentPropertiesReader();
+ result = ovfReader.readProperties(reader);
+ } catch (IOException ex) {
+ this.eventLogger.log(KernelLogEvents.OVF_READ_ERROR, ex, ovfFile.getAbsolutePath());
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+ return result;
+ }
+
+ private static class ConfigAdminProperty {
+
+ String pid;
+
+ String key;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BlockingSignal.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BlockingSignal.java
new file mode 100644
index 00000000..48560a4e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BlockingSignal.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.core;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+
+/**
+ * A <code>Signal</code> implementation that blocks until notified of completion.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public final class BlockingSignal implements Signal {
+
+ private final CountDownLatch latch = new CountDownLatch(1);
+
+ private final AtomicReference<Throwable> failure = new AtomicReference<Throwable>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public void signalFailure(Throwable cause) {
+ this.failure.set(cause);
+ this.latch.countDown();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void signalSuccessfulCompletion() {
+ this.latch.countDown();
+ }
+
+ public boolean awaitCompletion(long period, TimeUnit timeUnit) throws FailureSignalledException {
+ try {
+ if (!latch.await(period, timeUnit)) {
+ return false;
+ } else {
+ Throwable failure = this.failure.get();
+ if (failure != null) {
+ throw new FailureSignalledException(failure);
+ } else {
+ return true;
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new FailureSignalledException(e);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleStarter.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleStarter.java
new file mode 100644
index 00000000..bce3ec9a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleStarter.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.core;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+
+/**
+ * Provides a mechanism to start {@link Bundle bundles}, and wait until the <code>Bundle</code> is started, including
+ * any asynchronous creation of an application context.
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations <strong>must</strong> be thread safe.
+ *
+ */
+public interface BundleStarter {
+
+ /**
+ * Starts the supplied {@link Bundle}, driving the supplied signal upon successful or unsuccessful completion
+ * of start processing. If the <code>Bundle</code> constructs an application context, then the
+ * signal will not be driven until application context construction has completed.
+ *
+ * @param bundle the <code>Bundle</code> to start.
+ * @param signal the <code>Signal</code> to drive.
+ * @throws BundleException if Bundle {@link Bundle#start()} fails
+ */
+ void start(Bundle bundle, Signal signal) throws BundleException;
+
+ /**
+ * Starts the supplied {@link Bundle}, driving the supplied signal upon successful or unsuccessful completion
+ * of start processing. If the <code>Bundle</code> constructs an application context, then the
+ * signal will not be driven until application context construction has completed. The supplied <code>options</code>
+ * are passed to the <code>bundle</code>'s {@link Bundle#start() start} method.
+ *
+ * @param bundle the <code>Bundle</code> to start.
+ * @param options the options to be passed to the bundle's {@link Bundle#start() start} method.
+ * @param signal the <code>Signal</code> to drive.
+ * @throws BundleException
+ */
+ void start(Bundle bundle, int options, Signal signal) throws BundleException;
+
+ void trackStart(Bundle bundle, Signal signal);
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleUtils.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleUtils.java
new file mode 100644
index 00000000..8f66b75d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/BundleUtils.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.core;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.springframework.osgi.extender.support.ApplicationContextConfiguration;
+
+import org.eclipse.virgo.util.common.StringUtils;
+
+
+/**
+ * <code>BundleUtils</code> provides utility methods for interacting with {@link Bundle Bundles}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe
+ *
+ */
+public final class BundleUtils {
+
+ /**
+ * Queries whether the supplied {@link Bundle} is Spring-DM powered.
+ *
+ * @param bundle the <code>Bundle</code>.
+ * @return <code>true</code> if the <code>Bundle</code> is Spring-DM powered, otherwise <code>false</code>.
+ */
+ public static boolean isSpringOsgiPoweredBundle(Bundle bundle) {
+ return new ApplicationContextConfiguration(bundle).isSpringPoweredBundle();
+ }
+
+ /**
+ * Queries whether the supplied {@link Bundle} is a fragment
+ *
+ * @param bundle the <code>Bundle</code>.
+ * @return <code>true</code> if the <code>Bundle</code> is fragment, otherwise <code>false</code>.
+ */
+ // TODO Move this method into utils project
+ public static boolean isFragmentBundle(Bundle bundle) {
+ String fragmentHostHeader = (String) bundle.getHeaders().get(Constants.FRAGMENT_HOST);
+ return StringUtils.hasText(fragmentHostHeader);
+ }
+
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FailureSignalledException.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FailureSignalledException.java
new file mode 100644
index 00000000..d3aa8b34
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FailureSignalledException.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.core;
+
+
+/**
+ * A <code>FailureSignalledException</code> is used to indicate that a {@link BlockingSignal}
+ * has received a failure signal.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe
+ *
+ */
+public final class FailureSignalledException extends Exception {
+
+ private static final long serialVersionUID = -8980489442577132319L;
+
+ /**
+ * Creates a new <code>FailureSignalledException</code> with the supplied failure
+ * <code>cause</code>.
+ *
+ * @param cause the cause of the failure
+ */
+ public FailureSignalledException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FatalKernelException.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FatalKernelException.java
new file mode 100644
index 00000000..7c9197a1
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/FatalKernelException.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.core;
+
+import org.eclipse.virgo.kernel.serviceability.FatalServerException;
+
+//TODO: merge this with FatalServerException
+/**
+ * Signals an internal error in the kernel.<p/>
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Threadsafe.
+ *
+ */
+public class FatalKernelException extends FatalServerException {
+
+ private static final long serialVersionUID = 5023385710047479850L;
+
+ /**
+ * Creates a new <code>FatalKernelException</code>.
+ *
+ * @param message the error message.
+ */
+ public FatalKernelException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new <code>FatalKernelException</code>.
+ *
+ * @param message the error message.
+ * @param cause the root cause.
+ */
+ public FatalKernelException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/KernelException.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/KernelException.java
new file mode 100644
index 00000000..880bab8c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/KernelException.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.core;
+
+/**
+ * Signals an error detected by the kernel.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Threadsafe.
+ *
+ */
+public class KernelException extends Exception {
+
+ private static final long serialVersionUID = -8441774467715137666L;
+
+ /**
+ * Creates a new {@link KernelException}.
+ *
+ * @param message the error message.
+ */
+ public KernelException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new {@link KernelException}.
+ *
+ * @param message the error message.
+ * @param cause the root cause.
+ */
+ public KernelException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Shutdown.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Shutdown.java
new file mode 100644
index 00000000..a11a1d78
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Shutdown.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.core;
+
+import javax.management.MXBean;
+
+/**
+ * Shutdown control mechanism. Calling {@link #shutdown()} will shut the kernel down gracefully whereas
+ * {@link #immediateShutdown()} will kill the kernel immediately without performing any cleanup actions.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Implementations are <strong>required</strong> to be thread-safe.
+ *
+ */
+@MXBean
+public interface Shutdown {
+
+ /**
+ * Shuts down the Server immediately.
+ */
+ void immediateShutdown();
+
+ /**
+ * Shuts down the server in a graceful manner thereby minimising processing required during a subsequent restart.
+ */
+ void shutdown();
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Signal.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Signal.java
new file mode 100644
index 00000000..ea49b51a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/Signal.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.core;
+
+/**
+ * {@link Signal} is an interface for signalling successful or unsuccessful completion.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of this class must be thread safe.
+ *
+ */
+public interface Signal {
+
+ /**
+ * Notifies successful completion. If signalFailure has already been called, the behaviour is undefined.
+ */
+ void signalSuccessfulCompletion();
+
+ /**
+ * Notifies unsuccessful completion with the given {@link Throwable}. If signalCompletion has already been called,
+ * the behaviour is undefined.
+ *
+ * @param cause a <code>Throwable</code> describing the cause of unsuccessful completion
+ */
+ void signalFailure(Throwable cause);
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/AsyncShutdownDecorator.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/AsyncShutdownDecorator.java
new file mode 100644
index 00000000..3f253063
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/AsyncShutdownDecorator.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import org.eclipse.virgo.kernel.core.Shutdown;
+
+/**
+ * Decorator for a {@link Shutdown} implementation that performs all operations asynchronously.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+final class AsyncShutdownDecorator implements Shutdown {
+
+ private static final String THREAD_NAME = "kernel-shutdown";
+ private final Shutdown delegate;
+
+ public AsyncShutdownDecorator(Shutdown delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void immediateShutdown() {
+ new Thread(new Runnable() {
+
+ public void run() {
+ AsyncShutdownDecorator.this.delegate.immediateShutdown();
+ }
+
+ }, THREAD_NAME).start();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void shutdown() {
+ new Thread(new Runnable() {
+
+ public void run() {
+ AsyncShutdownDecorator.this.delegate.shutdown();
+ }
+
+ }, THREAD_NAME).start();
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/BundleStartTracker.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/BundleStartTracker.java
new file mode 100644
index 00000000..a20e51ee
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/BundleStartTracker.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.virgo.kernel.core.BundleUtils;
+import org.eclipse.virgo.kernel.core.Signal;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.osgi.extender.support.ApplicationContextConfiguration;
+
+
+/**
+ * <code>BundleStartTracker</code> tracks the startup of bundles, including any asynchronous portion of the startup,
+ * notifying a {@link Signal} upon completion (successful or otherwise).
+ *
+ * <p/>
+ *
+ * <strong>Note</strong> if the synchronous portion of startup fails, i.e. {@link Bundle#start()} does not return
+ * successfully the <code>Signal</code> is <strong>not</strong> driven and it is the responsibility of the caller of
+ * <code>start</code> to handle the failure.
+ *
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class BundleStartTracker implements EventHandler {
+
+ private static final String TOPIC_BLUEPRINT_EVENTS = "org/osgi/service/blueprint/container/";
+
+ private static final String EVENT_REGION_STARTING = "org/eclipse/virgo/kernel/region/STARTING";
+
+ private static final String EVENT_CREATED = TOPIC_BLUEPRINT_EVENTS + "CREATED";
+
+ private static final String EVENT_FAILURE = TOPIC_BLUEPRINT_EVENTS + "FAILURE";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(BundleStartTracker.class);
+
+ private final Object monitor = new Object();
+
+ private final List<Bundle> bundlesWithCreatedApplicationContexts = new ArrayList<Bundle>();
+
+ private final Map<Bundle, Throwable> failureMap = new HashMap<Bundle, Throwable>();
+
+ private final Map<Bundle, List<Signal>> signalMap = new HashMap<Bundle, List<Signal>>();
+
+ private final BundleListener bundleListener = new StartupTrackerBundleListener();
+
+ private final TaskExecutor signalExecutor;
+
+ BundleStartTracker(TaskExecutor signalExecutor) {
+ this.signalExecutor = signalExecutor;
+ }
+
+ void initialize(BundleContext bundleContext) {
+ bundleContext.addBundleListener(this.bundleListener);
+ }
+
+ private void recordApplicationContextCreation(Bundle bundle) {
+ LOGGER.info("Recording created application context for bundle '{}'", bundle);
+
+ synchronized (this.monitor) {
+ this.bundlesWithCreatedApplicationContexts.add(bundle);
+ }
+ }
+
+ private void driveSignalsIfStartCompleted(Bundle bundle, boolean springDmPowered) {
+
+ List<Signal> signals = null;
+ Throwable failure = null;
+ boolean isActive = isBundleActive(bundle);
+
+ synchronized (this.monitor) {
+ if (springDmPowered) {
+ boolean created = this.bundlesWithCreatedApplicationContexts.contains(bundle);
+ failure = this.failureMap.get(bundle);
+
+ if (created && failure != null) {
+ throw new IllegalStateException("Spring DM has notified an application context both successfully constructed and failed: " + failure);
+ }
+
+ if (created) {
+ LOGGER.info("Bundle '{}' has started and its application context is available", bundle);
+ signals = this.signalMap.remove(bundle);
+ } else if (failure != null) {
+ LOGGER.info("Bundle '{}' failed to start, the failure was '{}'", bundle, failure);
+ signals = this.signalMap.remove(bundle);
+ }
+ }
+ else {
+ if (isActive) {
+ signals = this.signalMap.remove(bundle);
+ }
+ }
+ }
+ // signals to drive
+ if (signals != null) {
+ if (!springDmPowered && isActive) {
+ LOGGER.info("Non-Spring DM powered bundle '{}' has started. Driving signals '{}'.", bundle, signals);
+ driveSignals(signals, null);
+ }
+ else {
+ driveSignals(signals, failure);
+ }
+ }
+ }
+
+ private void driveSignals(final List<Signal> signals, final Throwable cause) {
+ this.signalExecutor.execute(new Runnable() {
+ public void run() {
+ for (Signal signal : signals) {
+ LOGGER.info("Driving signal '{}'", signal);
+ if (cause == null) {
+ signal.signalSuccessfulCompletion();
+ } else {
+ signal.signalFailure(cause);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void handleEvent(Event event) {
+
+ LOGGER.info("Handling event '{}'", event);
+
+ Throwable cause = null;
+ List<Signal> signals = null;
+
+ Bundle bundle = (Bundle) event.getProperty("bundle");
+ if (EVENT_FAILURE.equals(event.getTopic())) {
+ cause = (Throwable) event.getProperty("exception");
+ if (cause != null) {
+ synchronized (this.monitor) {
+ LOGGER.error("Recording application context construction failure '{}' for bundle '{}'", cause, bundle);
+ this.failureMap.put(bundle, cause);
+ signals = this.signalMap.remove(bundle);
+ }
+ }
+ } else if (EVENT_CREATED.equals(event.getTopic())) {
+ synchronized (this.monitor) {
+ recordApplicationContextCreation(bundle);
+ signals = this.signalMap.remove(bundle);
+ }
+ } else if (EVENT_REGION_STARTING.equals(event.getTopic())) {
+ initialize((BundleContext) event.getProperty("region.bundleContext"));
+ }
+
+ if (signals != null) {
+ driveSignals(signals, cause);
+ }
+ }
+
+ public void trackStart(Bundle bundle, Signal signal) {
+ if (BundleUtils.isFragmentBundle(bundle)) {
+ throw new IllegalArgumentException("Cannot track the start of a fragment bundle.");
+ }
+
+ boolean springDmPowered = isSpringDmPoweredBundle(bundle);
+
+ boolean bundleActive = isBundleActive(bundle);
+
+ if (signal != null) {
+ if (springDmPowered || !bundleActive) {
+ List<Signal> queue;
+ synchronized (this.monitor) {
+ queue = this.signalMap.get(bundle);
+ if (queue == null) {
+ queue = new ArrayList<Signal>();
+ this.signalMap.put(bundle, queue);
+ }
+ LOGGER.info("Adding signal '{}' for bundle '{}'", signal, bundle);
+ queue.add(signal);
+ }
+ } else {
+ // !springDmPowered && bundleActive
+ driveSignals(Arrays.asList(signal), null);
+ }
+ }
+ driveSignalsIfStartCompleted(bundle, springDmPowered);
+ }
+
+ private static boolean isBundleActive(Bundle bundle) {
+ if (bundle!=null) {
+ return ( bundle.getState() == Bundle.ACTIVE );
+ }
+ return false;
+ }
+
+ private static boolean isSpringDmPoweredBundle(Bundle bundle) {
+ ApplicationContextConfiguration springDmConfiguration = new ApplicationContextConfiguration(bundle);
+ boolean springDmPowered = springDmConfiguration.isSpringPoweredBundle();
+ return springDmPowered;
+ }
+
+ private final class StartupTrackerBundleListener implements SynchronousBundleListener {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void bundleChanged(BundleEvent event) {
+ Bundle bundle = event.getBundle();
+ if (event.getType() == BundleEvent.STARTED) {
+ List<Signal> signals = null;
+ if (!isSpringDmPoweredBundle(bundle)) {
+ synchronized (BundleStartTracker.this.monitor) {
+ signals = BundleStartTracker.this.signalMap.remove(bundle);
+ }
+ if (signals != null) {
+ LOGGER.info("Non-Spring DM powered bundle '{}' has started. Driving signals '{}'.", bundle, signals);
+ driveSignals(signals, null);
+ }
+ }
+ }
+ if (event.getType() == BundleEvent.STOPPED) {
+ LOGGER.info("Bundle '{}' has stopped. Removing its related tracking state.", bundle);
+ BundleStartTracker.this.cleanup(bundle, new RuntimeException("bundle stopped"));
+ }
+ }
+ }
+
+ /**
+ * Remove tracking state associated with this bundle
+ * @param bundle whose tracking state is removed
+ * @param cause reason for cleaning up
+ */
+ public void cleanup(Bundle bundle, Throwable cause) {
+ List<Signal> danglingSignals = null;
+ synchronized (BundleStartTracker.this.monitor) {
+ if (bundle != null) {
+ BundleStartTracker.this.bundlesWithCreatedApplicationContexts.remove(bundle);
+ BundleStartTracker.this.failureMap.remove(bundle);
+ danglingSignals = BundleStartTracker.this.signalMap.remove(bundle);
+ }
+ }
+ if (danglingSignals != null) {
+ driveSignals(danglingSignals, cause);
+ }
+ }
+
+ /**
+ *
+ */
+ public void stop() {
+ if (this.signalExecutor instanceof DisposableBean) {
+ try {
+ ((DisposableBean) this.signalExecutor).destroy();
+ } catch (Exception e) {
+ LOGGER.debug("Failure when attempting to destroy signal executor", e);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivator.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivator.java
new file mode 100644
index 00000000..385e146d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivator.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import java.lang.management.ManagementFactory;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.JMException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.launch.Framework;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+
+import org.eclipse.virgo.kernel.config.internal.ConfigurationInitialiser;
+import org.eclipse.virgo.kernel.config.internal.KernelConfiguration;
+import org.eclipse.virgo.kernel.core.BundleStarter;
+import org.eclipse.virgo.kernel.core.Shutdown;
+import org.eclipse.virgo.kernel.core.internal.blueprint.ApplicationContextDependencyMonitor;
+import org.eclipse.virgo.kernel.shim.scope.ScopeFactory;
+import org.eclipse.virgo.kernel.shim.scope.internal.StandardScopeFactory;
+import org.eclipse.virgo.kernel.shim.serviceability.TracingService;
+import org.eclipse.virgo.kernel.shim.serviceability.internal.Slf4jTracingService;
+import org.eclipse.virgo.medic.dump.DumpGenerator;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.util.osgi.ServiceRegistrationTracker;
+
+/**
+ * {@link BundleActivator} that initialises the core of the Kernel.
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Threadsafe.
+ *
+ */
+public class CoreBundleActivator implements BundleActivator {
+
+ private static final String START_SIGNALLING_THREAD_NAME_PREFIX = "start-signalling-";
+
+ private static final String PROPERTY_NAME_SERVICE_SCOPE = "com.springsource.service.scope";
+
+ private static final String SERVICE_SCOPE_GLOBAL = "global";
+
+ private static final String EVENT_TOPIC_BLUEPRINT_CONTAINER = "org/osgi/service/blueprint/container/*";
+
+ private static final String EVENT_TOPIC_REGION = "org/eclipse/virgo/kernel/region/*";
+
+ private static final String MBEAN_VALUE_SHUTDOWN = "Shutdown";
+
+ private static final String MBEAN_KEY_TYPE = "type";
+
+ private static final int STARTUP_WAIT_LIMIT = 3600; // one hour
+
+ private final ServiceRegistrationTracker tracker = new ServiceRegistrationTracker();
+
+ private final ConfigurationInitialiser configurationInitialiser = new ConfigurationInitialiser();
+
+ private volatile StartupTracker startupTracker;
+
+ private volatile ObjectInstance shutdownMBean;
+
+ private volatile ApplicationContextDependencyMonitor dependencyMonitor;
+
+ private volatile BundleStartTracker bundleStartTracker;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start(BundleContext context) throws Exception {
+ EventLogger eventLogger = getRequiredService(context, EventLogger.class);
+
+ KernelConfiguration configuration = this.configurationInitialiser.start(context, eventLogger);
+ Shutdown shutdown = initializeShutdownManager(context, eventLogger, configuration);
+
+ this.bundleStartTracker = createAndRegisterBundleStartTracker(context);
+ createAndRegisterBundleStarter(this.bundleStartTracker, context);
+
+ this.dependencyMonitor = createAndRegisterApplicationContextDependencyMonitor(context, eventLogger);
+
+ DumpGenerator dumpGenerator = getRequiredService(context, DumpGenerator.class);
+
+ this.startupTracker = new StartupTracker(context, configuration, STARTUP_WAIT_LIMIT, bundleStartTracker, shutdown, dumpGenerator);
+ this.startupTracker.start();
+
+ initShimServices(context);
+ }
+
+ private ApplicationContextDependencyMonitor createAndRegisterApplicationContextDependencyMonitor(BundleContext context, EventLogger eventLogger) {
+ ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
+ private AtomicLong threadCount = new AtomicLong(1);
+
+ public Thread newThread(Runnable r) {
+ String name = "service-monitor-thread-" + this.threadCount.getAndIncrement();
+ return new Thread(r, name);
+ }
+ });
+
+ ApplicationContextDependencyMonitor dependencyMonitor = new ApplicationContextDependencyMonitor(scheduledExecutor, eventLogger);
+
+ Properties properties = new Properties();
+ properties.put(EventConstants.EVENT_TOPIC, EVENT_TOPIC_BLUEPRINT_CONTAINER);
+
+ this.tracker.track(context.registerService(EventHandler.class.getName(), dependencyMonitor, properties));
+
+ return dependencyMonitor;
+ }
+
+ @SuppressWarnings("unchecked")
+ private BundleStartTracker createAndRegisterBundleStartTracker(BundleContext context) {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setThreadNamePrefix(START_SIGNALLING_THREAD_NAME_PREFIX);
+ executor.setQueueCapacity(0);
+ executor.initialize();
+
+ BundleStartTracker asynchronousStartTracker = new BundleStartTracker(executor);
+ asynchronousStartTracker.initialize(context);
+
+ Dictionary properties = new Hashtable();
+ properties.put(EventConstants.EVENT_TOPIC, new String[] {EVENT_TOPIC_BLUEPRINT_CONTAINER, EVENT_TOPIC_REGION});
+
+ this.tracker.track(context.registerService(new String[] {EventHandler.class.getName()}, asynchronousStartTracker, properties));
+
+ return asynchronousStartTracker;
+ }
+
+ @SuppressWarnings("unchecked")
+ private BundleStarter createAndRegisterBundleStarter(BundleStartTracker asynchronousStartTracker, BundleContext bundleContext) {
+
+ StandardBundleStarter bundleStarter = new StandardBundleStarter(asynchronousStartTracker);
+ Dictionary properties = new Hashtable();
+ properties.put(PROPERTY_NAME_SERVICE_SCOPE, SERVICE_SCOPE_GLOBAL);
+
+ this.tracker.track(bundleContext.registerService(new String[] {BundleStarter.class.getName()}, bundleStarter, properties));
+
+ return bundleStarter;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stop(BundleContext context) throws Exception {
+ this.tracker.unregisterAll();
+ this.startupTracker.stop();
+ this.configurationInitialiser.stop();
+
+ unregisterShutdownMBean();
+
+ ApplicationContextDependencyMonitor dependencyMonitor = this.dependencyMonitor;
+ if (dependencyMonitor != null) {
+ this.dependencyMonitor = null;
+ dependencyMonitor.stop();
+ }
+
+ BundleStartTracker bundleStartTracker = this.bundleStartTracker;
+ if (bundleStartTracker != null) {
+ this.bundleStartTracker = null;
+ bundleStartTracker.stop();
+ }
+ }
+
+ private Shutdown initializeShutdownManager(BundleContext context, EventLogger eventLogger, KernelConfiguration configuration) {
+ Shutdown shutdown = createShutdown(context, eventLogger);
+ this.tracker.track(context.registerService(org.eclipse.virgo.kernel.core.Shutdown.class.getName(), shutdown, null));
+
+ registerShutdownMBean(configuration, shutdown);
+ return shutdown;
+ }
+
+ private void registerShutdownMBean(KernelConfiguration configuration, Shutdown shutdown) {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ try {
+ ObjectName shutdownName = ObjectName.getInstance(configuration.getDomain(), MBEAN_KEY_TYPE, MBEAN_VALUE_SHUTDOWN);
+ this.shutdownMBean = server.registerMBean(new AsyncShutdownDecorator(shutdown), shutdownName);
+ } catch (JMException ex) {
+ throw new IllegalStateException("Unable to register Shutdown MBean", ex);
+ }
+ }
+
+ private void unregisterShutdownMBean() throws MBeanRegistrationException, InstanceNotFoundException {
+ ObjectInstance localShutdownMBean = this.shutdownMBean;
+ if (localShutdownMBean != null) {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(localShutdownMBean.getObjectName());
+ this.shutdownMBean = null;
+ }
+ }
+
+ protected Shutdown createShutdown(BundleContext context, EventLogger eventLogger) {
+ Framework framework = (Framework) context.getBundle(0);
+
+ ShutdownManager manager = new ShutdownManager(eventLogger, framework);
+ return manager;
+ }
+
+ private void initShimServices(BundleContext context) {
+ ScopeFactory scopeFactory = new StandardScopeFactory();
+ TracingService tracingService = new Slf4jTracingService();
+ this.tracker.track(context.registerService(ScopeFactory.class.getName(), scopeFactory, null));
+ this.tracker.track(context.registerService(TracingService.class.getName(), tracingService, null));
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> T getRequiredService(BundleContext context, Class<T> clazz) {
+ T result = null;
+ ServiceReference ref = context.getServiceReference(clazz.getName());
+ if (ref != null) {
+ result = (T) context.getService(ref);
+ }
+ if (result == null) {
+ throw new IllegalStateException("Unable to access required service of type '" + clazz.getName() + "' from bundle '"
+ + context.getBundle().getSymbolicName() + "'");
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatus.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatus.java
new file mode 100644
index 00000000..409c86ba
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatus.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+final class KernelStatus implements KernelStatusMBean {
+
+ static final String STATUS_STARTING = "STARTING";
+
+ static final String STATUS_STARTED = "STARTED";
+
+ private volatile String status = STATUS_STARTING;
+
+ public String getStatus() {
+ return this.status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatusMBean.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatusMBean.java
new file mode 100644
index 00000000..58647b6a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/KernelStatusMBean.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+/**
+ * MBean for kernel status.
+ *
+ */
+public interface KernelStatusMBean {
+
+ String getStatus();
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/ShutdownManager.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/ShutdownManager.java
new file mode 100644
index 00000000..cc0bfef7
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/ShutdownManager.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.framework.launch.Framework;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+import org.eclipse.virgo.kernel.core.Shutdown;
+import org.eclipse.virgo.kernel.diagnostics.KernelLogEvents;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+
+/**
+ * Standard implementation of {@link Shutdown} that performs all shutdown actions synchronously.
+ * <p />
+ * This implementation registers a {@link Runtime#addShutdownHook(Thread) shutdown hook} to perform graceful shutdown
+ * when the user kills the VM.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe
+ *
+ */
+class ShutdownManager implements Shutdown {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ShutdownManager.class);
+
+ private static final long SHUTDOWN_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
+
+ private static final int STATE_RUNNING = 0;
+
+ private static final int STATE_STOPPING = 1;
+
+ private final AtomicInteger state = new AtomicInteger(STATE_RUNNING);
+
+ private final EventLogger eventLogger;
+
+ private final Framework framework;
+
+ private final Thread shutdownHook = new Thread(new Runnable() {
+
+ public void run() {
+ try {
+ // set to stopping so we don't try to remove the shutdown hook later
+ state.set(STATE_STOPPING);
+ ShutdownManager.this.shutdown();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ });
+
+ public ShutdownManager(EventLogger eventLogger, Framework framework) {
+ this.eventLogger = eventLogger;
+ this.framework = framework;
+ Runtime.getRuntime().addShutdownHook(this.shutdownHook);
+ BundleContext bundleContext = framework.getBundleContext();
+ bundleContext.addBundleListener(new ShutdownLoggingListener());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void shutdown() {
+ FrameworkEvent shutdownResponse = null;
+ try {
+ this.framework.stop();
+ shutdownResponse = this.framework.waitForStop(SHUTDOWN_TIMEOUT);
+ } catch (BundleException ex) {
+ LOGGER.error("Error during shutdown.", ex);
+ } catch (InterruptedException ex) {
+ LOGGER.error("Interrupted during shutdown.", ex);
+ }
+
+ if (!isSuccessfulStopResponse(shutdownResponse)) {
+ immediateShutdown();
+ } else {
+ removeShutdownHook();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void immediateShutdown() {
+ removeShutdownHook();
+ this.eventLogger.log(KernelLogEvents.IMMEDIATE_SHUTDOWN_INITIATED);
+ exitVM();
+ }
+
+ protected void exitVM() {
+ System.exit(0);
+ }
+
+ private boolean isSuccessfulStopResponse(FrameworkEvent shutdownResponse) {
+ return shutdownResponse != null && shutdownResponse.getType() == FrameworkEvent.STOPPED;
+ }
+
+ private void removeShutdownHook() {
+ if(this.state.compareAndSet(STATE_RUNNING, STATE_STOPPING)) {
+ Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
+ }
+ }
+
+ private final class ShutdownLoggingListener implements SynchronousBundleListener {
+
+ public void bundleChanged(BundleEvent event) {
+ BundleContext bundleContext = ShutdownManager.this.framework.getBundleContext();
+ if (BundleEvent.STOPPING == event.getType() && event.getBundle() == bundleContext.getBundle()) {
+ ShutdownManager.this.eventLogger.log(KernelLogEvents.SHUTDOWN_INITIATED);
+ removeShutdownHook();
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StandardBundleStarter.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StandardBundleStarter.java
new file mode 100644
index 00000000..7eca0d0e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StandardBundleStarter.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import org.eclipse.virgo.kernel.core.BundleStarter;
+import org.eclipse.virgo.kernel.core.BundleUtils;
+import org.eclipse.virgo.kernel.core.Signal;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+
+/**
+ * Standard implementation of {@link BundleStarter} that starts the bundle and delegates to a {@link BundleStartTracker}
+ * to track any asynchronous portion of the bundle's startup.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class StandardBundleStarter implements BundleStarter {
+
+ private final BundleStartTracker bundleStartTracker;
+
+ private static final int DEFAULT_START_OPTIONS = 0;
+
+ public StandardBundleStarter(BundleStartTracker bundleStartTracker) {
+ this.bundleStartTracker = bundleStartTracker;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start(Bundle bundle, Signal signal) throws BundleException {
+ start(bundle, DEFAULT_START_OPTIONS, signal);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start(Bundle bundle, int options, Signal signal) throws BundleException {
+
+ trackStart(bundle, signal);
+
+ if (bundleNeedsStarting(bundle)) {
+ try {
+ bundle.start(options);
+ } catch (BundleException be) {
+ this.bundleStartTracker.cleanup(bundle, be);
+ throw be;
+ }
+ }
+ }
+
+ private static boolean bundleNeedsStarting(Bundle bundle) {
+ if (bundle != null) {
+ int bundleState = bundle.getState();
+ return (bundleState != Bundle.STARTING && bundleState != Bundle.ACTIVE);
+ }
+ return false;
+ }
+
+ public void trackStart(Bundle bundle, Signal signal) {
+ if (BundleUtils.isFragmentBundle(bundle)) {
+ throw new IllegalArgumentException("A fragment bundle cannot be started and so start cannot be tracked");
+ }
+
+ if (signal != null) {
+ this.bundleStartTracker.trackStart(bundle, signal);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StartupTracker.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StartupTracker.java
new file mode 100644
index 00000000..aa92a843
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/StartupTracker.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+import org.eclipse.virgo.kernel.config.internal.KernelConfiguration;
+import org.eclipse.virgo.kernel.core.BlockingSignal;
+import org.eclipse.virgo.kernel.core.BundleUtils;
+import org.eclipse.virgo.kernel.core.FailureSignalledException;
+import org.eclipse.virgo.kernel.core.FatalKernelException;
+import org.eclipse.virgo.kernel.core.Shutdown;
+import org.eclipse.virgo.kernel.diagnostics.KernelLogEvents;
+import org.eclipse.virgo.medic.dump.DumpGenerator;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+
+/**
+ * <code>StartupTracker</code> tracks the startup of the Kernel and produces event log entries, and
+ * {@link EventAdmin} events as the kernel starts.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class StartupTracker {
+
+ private static final String THREAD_NAME_STARTUP_TRACKER = "startup-tracker";
+
+ static final String APPLICATION_CONTEXT_FILTER = "(objectClass=org.springframework.context.ApplicationContext)";
+
+ private static final String KERNEL_EVENT_TOPIC = "org/eclipse/virgo/kernel/";
+
+ private static final String KERNEL_EVENT_STARTING = KERNEL_EVENT_TOPIC + "STARTING";
+
+ private static final String KERNEL_EVENT_STARTED = KERNEL_EVENT_TOPIC + "STARTED";
+
+ private static final String KERNEL_EVENT_START_TIMED_OUT = KERNEL_EVENT_TOPIC + "START_TIMED_OUT";
+
+ private static final String KERNEL_EVENT_START_FAILED = KERNEL_EVENT_TOPIC + "START_FAILED";
+
+ private static final String KERNEL_BSN_PREFIX = "org.eclipse.virgo.kernel";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StartupTracker.class);
+
+ private final KernelStatus status = new KernelStatus();
+
+ private final KernelConfiguration configuration;
+
+ private final Thread startupTrackingThread;
+
+ private final Shutdown shutdown;
+
+ private final DumpGenerator dumpGenerator;
+
+ private volatile ObjectInstance statusInstance;
+
+ StartupTracker(BundleContext context, KernelConfiguration configuration, int startupWaitTime, BundleStartTracker asyncBundleStartTracker, Shutdown shutdown, DumpGenerator dumpGenerator) {
+ Runnable startupTrackingRunnable = new StartupTrackingRunnable(context, startupWaitTime, asyncBundleStartTracker);
+ this.startupTrackingThread = new Thread(startupTrackingRunnable, THREAD_NAME_STARTUP_TRACKER);
+ this.configuration = configuration;
+ this.shutdown = shutdown;
+ this.dumpGenerator = dumpGenerator;
+ }
+
+ void start() {
+ registerKernelStatusMBean();
+ this.startupTrackingThread.start();
+ }
+
+ void stop() {
+ unregisterKernelStatusMBean();
+ }
+
+ private void registerKernelStatusMBean() {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ try {
+ ObjectName name = ObjectName.getInstance(StartupTracker.this.configuration.getDomain(), "type", "KernelStatus");
+ this.statusInstance = server.registerMBean(this.status, name);
+ } catch (JMException e) {
+ throw new FatalKernelException("Unable to register KernelStatus MBean", e);
+ }
+ }
+
+ private void unregisterKernelStatusMBean() {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ try {
+ ObjectInstance instance = this.statusInstance;
+ if (instance != null && server.isRegistered(instance.getObjectName())) {
+ server.unregisterMBean(this.statusInstance.getObjectName());
+ }
+ } catch (JMException e) {
+ throw new FatalKernelException("Unable to unregister KernelStatus MBean", e);
+ }
+ }
+
+ private void signalStarted() {
+ this.status.setStatus(KernelStatus.STATUS_STARTED);
+ }
+
+ private final class StartupTrackingRunnable implements Runnable {
+
+ private final BundleContext context;
+
+ private final int startupWaitTime;
+
+ private final BundleStartTracker asyncBundleStartTracker;
+
+ private StartupTrackingRunnable(BundleContext context, int startupWaitTime, BundleStartTracker asyncBundleStartTracker) {
+ this.context = context;
+ this.startupWaitTime = startupWaitTime;
+ this.asyncBundleStartTracker = asyncBundleStartTracker;
+ }
+
+ public void run() {
+
+ kernelStarting();
+
+ Bundle[] bundles = this.context.getBundles();
+
+ try {
+ for (Bundle bundle : bundles) {
+ if (!BundleUtils.isFragmentBundle(bundle) && isKernelBundle(bundle)) {
+ BlockingSignal signal = new BlockingSignal();
+
+ this.asyncBundleStartTracker.trackStart(bundle, signal);
+
+ LOGGER.debug("Awaiting signal {} for up to {} seconds", signal, this.startupWaitTime);
+
+ if (!signal.awaitCompletion(this.startupWaitTime, TimeUnit.SECONDS)) {
+ LOGGER.error("Bundle {} did not start within {} seconds.", bundle, this.startupWaitTime);
+ kernelStartTimedOut();
+ return;
+ }
+ }
+ }
+ } catch (FailureSignalledException fse) {
+ kernelStartFailed(fse.getCause());
+ return;
+ } catch (Exception e) {
+ kernelStartFailed(e);
+ return;
+ }
+
+ kernelStarted();
+ }
+
+ private boolean isKernelBundle(Bundle bundle) {
+ String symbolicName = bundle.getSymbolicName();
+ return symbolicName != null && symbolicName.startsWith(KERNEL_BSN_PREFIX);
+ }
+
+ private void kernelStarting() {
+ postEvent(KERNEL_EVENT_STARTING);
+ logEvent(KernelLogEvents.KERNEL_STARTING);
+ }
+
+ private void kernelStarted() {
+ signalStarted();
+ postEvent(KERNEL_EVENT_STARTED);
+ logEvent(KernelLogEvents.KERNEL_STARTED);
+ }
+
+ private void kernelStartTimedOut() {
+ postEvent(KERNEL_EVENT_START_TIMED_OUT);
+ logEvent(KernelLogEvents.KERNEL_START_TIMED_OUT, this.startupWaitTime);
+ generateDumpAndShutdown("startupTimedOut", null);
+ }
+
+ private void kernelStartFailed(Throwable failure) {
+ postEvent(KERNEL_EVENT_START_FAILED);
+ logEvent(KernelLogEvents.KERNEL_START_FAILED, failure);
+ generateDumpAndShutdown("startupFailed", failure);
+ }
+
+ private void generateDumpAndShutdown(String cause, Throwable failure) {
+ if (failure != null) {
+ StartupTracker.this.dumpGenerator.generateDump(cause, failure);
+ } else {
+ StartupTracker.this.dumpGenerator.generateDump(cause);
+ }
+ StartupTracker.this.shutdown.immediateShutdown();
+ }
+
+ private void logEvent(KernelLogEvents event, Throwable throwable, Object...args) {
+ ServiceReference serviceReference = this.context.getServiceReference(EventLogger.class.getName());
+ if (serviceReference != null) {
+ EventLogger eventLogger = (EventLogger) this.context.getService(serviceReference);
+ if (eventLogger != null) {
+ eventLogger.log(event, throwable, args);
+ this.context.ungetService(serviceReference);
+ }
+ }
+ }
+
+ private void logEvent(KernelLogEvents event, Object... args) {
+ this.logEvent(event, null, args);
+ }
+
+ private void postEvent(String topic) {
+ ServiceReference serviceReference = this.context.getServiceReference(EventAdmin.class.getName());
+ if (serviceReference != null) {
+ EventAdmin eventAdmin = (EventAdmin) this.context.getService(serviceReference);
+ if (eventAdmin != null) {
+ eventAdmin.postEvent(new Event(topic, null));
+ this.context.ungetService(serviceReference);
+ }
+ }
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitor.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitor.java
new file mode 100644
index 00000000..78cabdf2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitor.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * 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.core.internal.blueprint;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.virgo.kernel.diagnostics.KernelLogEvents;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+
+/**
+ * {@link ApplicationContextDependencyMonitor} is a class that tracks the satisfaction of service dependencies needed
+ * during the creation of application contexts and issues log messages for delayed service dependencies.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This class is thread safe.
+ *
+ */
+public final class ApplicationContextDependencyMonitor implements EventHandler {
+
+ private static final String TOPIC_BLUEPRINT_EVENTS = "org/osgi/service/blueprint/container/";
+
+ private static final String EVENT_WAITING = TOPIC_BLUEPRINT_EVENTS + "WAITING";
+
+ private static final String EVENT_GRACE_PERIOD = TOPIC_BLUEPRINT_EVENTS + "GRACE_PERIOD";
+
+ private static final String EVENT_FAILURE = TOPIC_BLUEPRINT_EVENTS + "FAILURE";
+
+ private static final String EVENT_CREATED = TOPIC_BLUEPRINT_EVENTS + "CREATED";
+
+ private static final int MAXIMUM_WARNING_INTERVAL = 60 * 1000;
+
+ private static final int WARNING_INTERVAL_INCREASE_RATE_PERCENT = 200;
+
+ private static final int INITIAL_WARNING_INTERVAL = 5 * 1000;
+
+ private static final int SLOW_WARNING_INTERVAL = 5 * 60 * 1000;
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final EventLogger eventLogger;
+
+ private final ScheduledExecutorService scheduledExecutorService;
+
+ private final Map<Bundle, Map<ServiceDependency, Ticker>> tickers = new HashMap<Bundle, Map<ServiceDependency, Ticker>>();
+
+ private final Object monitor = new Object();
+
+ /**
+ * Construct a {@link ApplicationContextDependencyMonitor} which uses the given {@link ScheduledExecutorService} to
+ * schedule its warning messages.
+ *
+ * @param scheduledExecutorService the {@link ScheduledExecutorService} for scheduling warning messages
+ * @param eventLogger
+ */
+ public ApplicationContextDependencyMonitor(ScheduledExecutorService scheduledExecutorService, EventLogger eventLogger) {
+ this.scheduledExecutorService = scheduledExecutorService;
+ this.eventLogger = eventLogger;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void handleEvent(Event event) {
+ synchronized (this.monitor) {
+ Bundle bundle = (Bundle) event.getProperty(EventConstants.BUNDLE);
+
+ if (EVENT_WAITING.equals(event.getTopic())) {
+ List<ServiceDependency> serviceDependencies = createServiceDependencies(event);
+ for (ServiceDependency serviceDependency : serviceDependencies) {
+ addServiceDependencyTicker(serviceDependency, bundle);
+ }
+ } else if (EVENT_GRACE_PERIOD.equals(event.getTopic())) {
+ List<ServiceDependency> remainingUnsatisfiedDependencies = createServiceDependencies(event);
+ changeInUnsatisfiedDependencies(remainingUnsatisfiedDependencies, bundle);
+
+ } else if (EVENT_FAILURE.equals(event.getTopic())) {
+ String[] dependenciesArray = (String[]) event.getProperty("dependencies");
+ if (dependenciesArray != null) {
+ List<ServiceDependency> serviceDependencies = createServiceDependencies(event);
+ serviceDependenciesTimedOut(serviceDependencies, bundle);
+ } else {
+ containerCreationFailed(bundle);
+ }
+ } else if (EVENT_CREATED.equals(event.getTopic())) {
+ containerCreated(bundle);
+ }
+ }
+ }
+
+ private void serviceDependenciesTimedOut(List<ServiceDependency> timedOutDependencies, Bundle bundle) {
+ Map<ServiceDependency, Ticker> bundlesTickers = this.tickers.get(bundle);
+
+ if (bundlesTickers != null) {
+ for (ServiceDependency timedOutDependency : timedOutDependencies) {
+ Ticker ticker = bundlesTickers.remove(timedOutDependency);
+ if (ticker != null) {
+ dependencyTimedOut(timedOutDependency, ticker, bundle);
+ }
+ }
+ }
+ }
+
+ private void containerCreationFailed(Bundle bundle) {
+ Map<ServiceDependency, Ticker> tickers = this.tickers.remove(bundle);
+ if (tickers != null) {
+ for (Entry<ServiceDependency, Ticker> ticker : tickers.entrySet()) {
+ ticker.getValue().cancel();
+ }
+ }
+ }
+
+ private void containerCreated(Bundle bundle) {
+ Map<ServiceDependency, Ticker> bundlesTickers = this.tickers.remove(bundle);
+
+ if (bundlesTickers != null) {
+ for (Entry<ServiceDependency, Ticker> entry : bundlesTickers.entrySet()) {
+ dependencySatisfied(entry.getKey(), entry.getValue(), bundle);
+ }
+ }
+ }
+
+ private void changeInUnsatisfiedDependencies(List<ServiceDependency> remainingUnsatisfiedDependencies, Bundle bundle) {
+ Map<ServiceDependency, Ticker> tickers = this.tickers.get(bundle);
+
+ if (tickers != null) {
+ Iterator<Entry<ServiceDependency, Ticker>> entries = tickers.entrySet().iterator();
+
+ while (entries.hasNext()) {
+ Entry<ServiceDependency, Ticker> entry = entries.next();
+
+ if (!remainingUnsatisfiedDependencies.contains(entry.getKey())) {
+ dependencySatisfied(entry.getKey(), entry.getValue(), bundle);
+ entries.remove();
+ }
+ }
+ }
+ }
+
+ private void dependencySatisfied(ServiceDependency serviceDependency, Ticker ticker, Bundle bundle) {
+ logger.info("Service dependency '{}' has been satisfied", serviceDependency);
+ handleRemovedTicker(ticker, serviceDependency, bundle, true);
+ }
+
+ private void dependencyTimedOut(ServiceDependency serviceDependency, Ticker ticker, Bundle bundle) {
+ logger.info("Service dependency '{}' has timed out", serviceDependency);
+ handleRemovedTicker(ticker, serviceDependency, bundle, false);
+ }
+
+ private void handleRemovedTicker(Ticker ticker, ServiceDependency serviceDependency, Bundle bundle, boolean satisfied) {
+ boolean hasTicked = ticker.cancel();
+ if (hasTicked) {
+ if (satisfied) {
+ this.eventLogger.log(KernelLogEvents.APPLICATION_CONTEXT_DEPENDENCY_SATISFIED, serviceDependency.getBeanName(),
+ bundle.getSymbolicName(), bundle.getVersion(), serviceDependency.getFilter());
+ } else {
+ this.eventLogger.log(KernelLogEvents.APPLICATION_CONTEXT_DEPENDENCY_TIMED_OUT, serviceDependency.getBeanName(),
+ bundle.getSymbolicName(), bundle.getVersion(), serviceDependency.getFilter());
+ }
+ }
+ }
+
+ /**
+ * Add a service dependency ticker for the given application context, given associated bundle, and given service
+ * dependency.
+ *
+ * @param applicationContext the partially constructed application context which needs the service dependency
+ * @param serviceDependency the service dependency
+ * @param bundle the {@link Bundle} associated with the given application context
+ */
+ private void addServiceDependencyTicker(final ServiceDependency serviceDependency, final Bundle bundle) {
+ Map<ServiceDependency, Ticker> serviceDependencyTickers = getServiceDependencyTickers(bundle);
+ if (serviceDependencyTickers.containsKey(serviceDependency)) {
+ logger.warn("Service dependency '{}' already being waited upon", serviceDependency);
+ } else {
+ // Services which are flagged as likely to be slow to be published are given a longer initial warning
+ // interval.
+ boolean slowService = serviceDependency.getFilter().contains("(org.eclipse.virgo.server.slowservice=true)");
+ serviceDependencyTickers.put(serviceDependency, StandardTicker.createExponentialTicker(slowService ? SLOW_WARNING_INTERVAL
+ : INITIAL_WARNING_INTERVAL, WARNING_INTERVAL_INCREASE_RATE_PERCENT, slowService ? SLOW_WARNING_INTERVAL : MAXIMUM_WARNING_INTERVAL,
+ new Callable<Void>() {
+
+ public Void call() throws Exception {
+ synchronized (ApplicationContextDependencyMonitor.this.monitor) {
+ eventLogger.log(KernelLogEvents.APPLICATION_CONTEXT_DEPENDENCY_DELAYED, serviceDependency.getBeanName(),
+ bundle.getSymbolicName(), bundle.getVersion(), serviceDependency.getFilter());
+ return null;
+ }
+ }
+ }, this.scheduledExecutorService));
+ }
+ }
+
+ /**
+ * Get the possibly empty map of service dependency tickers for the given <code>Bundle</code>.
+ *
+ * @param bundle the <code>Bundle</code> whose application context's service dependencies are required
+ * @return a map of service dependency tickers
+ */
+ private Map<ServiceDependency, Ticker> getServiceDependencyTickers(Bundle bundle) {
+ Map<ServiceDependency, Ticker> tickers = this.tickers.get(bundle);
+ if (tickers == null) {
+ tickers = new HashMap<ServiceDependency, Ticker>();
+ this.tickers.put(bundle, tickers);
+ }
+ return tickers;
+ }
+
+ public void stop() {
+ this.scheduledExecutorService.shutdown();
+ }
+
+ private List<ServiceDependency> createServiceDependencies(Event event) {
+ String[] filters = (String[]) event.getProperty("dependencies");
+ String[] beanNames = (String[]) event.getProperty("bean.name");
+
+ List<ServiceDependency> serviceDependencies = new ArrayList<ServiceDependency>();
+
+ if (filters != null) {
+ for (int i = 0; i < filters.length; i++) {
+ serviceDependencies.add(new ServiceDependency(filters[i], beanNames[i]));
+ }
+ }
+
+ return serviceDependencies;
+ }
+
+ private static final class ServiceDependency {
+
+ private final String filter;
+
+ private final String beanName;
+
+ private ServiceDependency(String filter, String beanName) {
+ this.filter = filter;
+ this.beanName = beanName;
+ }
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public String getBeanName() {
+ return beanName;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + beanName.hashCode();
+ result = prime * result + filter.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+
+ ServiceDependency other = (ServiceDependency) obj;
+
+ if (!beanName.equals(other.beanName))
+ return false;
+
+ if (!filter.equals(other.filter))
+ return false;
+
+ return true;
+ }
+
+ public String toString() {
+ return this.filter + " " + this.beanName;
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/StandardTicker.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/StandardTicker.java
new file mode 100644
index 00000000..e5cf63da
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/StandardTicker.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * 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.core.internal.blueprint;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.springframework.util.Assert;
+
+
+
+/**
+ * {@link StandardTicker} provides a heart-beat for tracking unanticipated delays. The heart-beat is configurable using a
+ * policy such as {@link ExponentialHeartBeatPolicy} which lengthens the heart-beat interval exponentially over time
+ * until it reaches a fixed upper bound. On each heart-beat until the ticker is cancelled, an action is called.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This class is thread safe.
+ *
+ * @param <V> the result type of the action taken on each heart-beat
+ */
+public final class StandardTicker<V> implements Ticker, Callable<V> {
+
+ private static final long OVERDUE = -1;
+
+ private final long creationTimeMillis;
+
+ private long lastTickMillis;
+
+ private final HeartBeatPolicy heartBeatPolicy;
+
+ private long heartBeatIntervalMillis;
+
+ private boolean tickedAtLeastOnce = false;
+
+ private boolean cancelled = false;
+
+ private ScheduledFuture<V> scheduledFuture;
+
+ private final Callable<V> action;
+
+ private final ScheduledExecutorService scheduledExecutorService;
+
+ private Object monitor = new Object();
+
+ /**
+ * Create a {@link Ticker} with the given heart-beat policy, action to be called on each tick, and executor service
+ * for scheduling ticks and set it ticking.
+ *
+ * @param <V> the action's result type
+ * @param heartBeatPolicy a policy which determines the possibly variable intervals between heartbeats
+ * @param action the thread safe action to be called on each tick
+ * @param scheduledExecutorService the executor service for scheduling ticks
+ * @return the constructed and ticking ticker
+ */
+ public static <V> Ticker createTicker(HeartBeatPolicy heartBeatPolicy, Callable<V> action, ScheduledExecutorService scheduledExecutorService) {
+ StandardTicker<V> ticker = new StandardTicker<V>(heartBeatPolicy, action, scheduledExecutorService);
+ ticker.start();
+ return ticker;
+ }
+
+ /**
+ * Create a {@link Ticker} with an exponential heart beat policy and a given action to be called on each tick and an
+ * executor service for scheduling ticks and set it ticking. The exponential heart beat policy has the given initial
+ * interval which then increases by the given percentage on each tick until the given maximum interval is reached.
+ *
+ * @param <V> the action's result type
+ * @param initialHeartbeatIntervalMillis the initial interval
+ * @param heartBeatIncreasePercentage the percentage increase on each tick
+ * @param maxHeartBeatIntervalMillis the maximum interval
+ * @param action the thread safe action to be called on each tick
+ * @param scheduledExecutorService the executor service for scheduling ticks
+ * @return the constructed and ticking ticker
+ */
+ public static <V> Ticker createExponentialTicker(long initialHeartbeatIntervalMillis, long heartBeatIncreasePercentage,
+ long maxHeartBeatIntervalMillis, Callable<V> action, ScheduledExecutorService scheduledExecutorService) {
+ return createTicker(new ExponentialHeartBeatPolicy(initialHeartbeatIntervalMillis, heartBeatIncreasePercentage, maxHeartBeatIntervalMillis),
+ action, scheduledExecutorService);
+ }
+
+ /**
+ * Construct a Ticker with the given heart beat policy, action to be called on each tick, and executor service for
+ * scheduling ticks.
+ *
+ * @param heartBeatPolicy a policy which determines the possibly variable intervals between heartbeats
+ * @param action the thread safe action to be called on each tick
+ * @param scheduledExecutorService the executor service for scheduling ticks
+ */
+ private StandardTicker(HeartBeatPolicy heartBeatPolicy, Callable<V> action, ScheduledExecutorService scheduledExecutorService) {
+ this.heartBeatPolicy = heartBeatPolicy;
+ this.heartBeatIntervalMillis = this.heartBeatPolicy.getNextHeartBeatIntervalMillis();
+ this.creationTimeMillis = System.currentTimeMillis();
+ this.lastTickMillis = this.creationTimeMillis;
+ this.action = action;
+ this.scheduledExecutorService = scheduledExecutorService;
+ }
+
+ /**
+ * Start this ticker ticking.
+ */
+ private void start() {
+ if (getIntervalToNextTickMillis() == OVERDUE) {
+ try {
+ this.call();
+ } catch (Exception e) {
+ }
+ } else {
+ scheduleNextTick();
+ }
+ }
+
+ /**
+ * Schedule the next tick of this ticker.
+ */
+ private void scheduleNextTick() {
+ synchronized (this.monitor) {
+ if (!this.cancelled) {
+ this.scheduledFuture = this.scheduledExecutorService.schedule(this, getIntervalToNextTickMillis(), TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public V call() throws Exception {
+ boolean ticked = tick();
+ scheduleNextTick();
+ return ticked ? this.action.call() : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean cancel() {
+ synchronized (this.monitor) {
+ this.cancelled = true;
+ this.scheduledFuture.cancel(true);
+ return this.tickedAtLeastOnce;
+ }
+ }
+
+ /**
+ * Determine whether a tick is due and, if so, update the ticker state to count down to the next tick and return
+ * <code>true</code>. If no tick is due, do not update the ticker state and return <code>false</code>.
+ *
+ * @return <code>true</code> if and only if the ticker tickedAtLeastOnce
+ */
+ private boolean tick() {
+ synchronized (this.monitor) {
+ boolean ticked = false;
+ if (!cancelled && getIntervalToNextTickMillis() == OVERDUE) {
+ ticked = true;
+ this.lastTickMillis = getCurrentTimeMillis();
+ this.heartBeatIntervalMillis = this.heartBeatPolicy.getNextHeartBeatIntervalMillis();
+ }
+ this.tickedAtLeastOnce = this.tickedAtLeastOnce || ticked;
+ return ticked;
+ }
+ }
+
+ /**
+ * Get the current time.
+ *
+ * Pre-condition: the monitor must be held.
+ *
+ * Post-condition: result >= this.lastTickMillis.
+ *
+ * @return the current time in milliseconds
+ */
+ private long getCurrentTimeMillis() {
+ long currentTimeMillis = System.currentTimeMillis();
+ Assert.isTrue(currentTimeMillis >= this.lastTickMillis, "Time must not go backwards");
+ return currentTimeMillis;
+ }
+
+ /**
+ * Get the time interval until the next tick is due, or OVERDUE if the next tick is overdue.
+ *
+ * @return the time interval in milliseconds, or OVERDUE if the next tick is overdue
+ */
+ private long getIntervalToNextTickMillis() {
+ synchronized (this.monitor) {
+ long intervalSinceLastTickMillis = getCurrentTimeMillis() - this.lastTickMillis;
+ return intervalSinceLastTickMillis < this.heartBeatIntervalMillis ? this.heartBeatIntervalMillis - intervalSinceLastTickMillis : OVERDUE;
+ }
+ }
+
+ /**
+ * {@link ExponentialHeartBeatPolicy} is a {@link HeartBeatPolicy} which returns intervals starting with a given
+ * initial interval and increasing by a given percentage up to a given maximum interval.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This class is thread safe.
+ */
+ private final static class ExponentialHeartBeatPolicy implements HeartBeatPolicy {
+
+ private final long maxHeartBeatIntervalMillis;
+
+ private final long heartBeatIncreasePercentage;
+
+ private AtomicLong heartBeatIntervalMillis;
+
+ /**
+ * Construct a {@link Ticker.HeartBeatPolicy HeartBeatPolicy} which the given initial interval which then increases by the given
+ * percentage on each tick until the given maximum interval is reached.
+ *
+ * @param initialHeartbeatIntervalMillis the initial interval
+ * @param heartBeatIncreasePercentage the percentage increase on each tick
+ * @param maxHeartBeatIntervalMillis the maximum interval
+ */
+ public ExponentialHeartBeatPolicy(long initialHeartbeatIntervalMillis, long heartBeatIncreasePercentage, long maxHeartBeatIntervalMillis) {
+ this.heartBeatIntervalMillis = new AtomicLong(initialHeartbeatIntervalMillis);
+ this.heartBeatIncreasePercentage = heartBeatIncreasePercentage;
+ this.maxHeartBeatIntervalMillis = maxHeartBeatIntervalMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getNextHeartBeatIntervalMillis() {
+ boolean success = false;
+ long nextHeartBeatIntervalMillis = 0;
+ while (!success) {
+ nextHeartBeatIntervalMillis = this.heartBeatIntervalMillis.get();
+ if (nextHeartBeatIntervalMillis < maxHeartBeatIntervalMillis) {
+ long newHeartBeatIntervalMillis = Math.min((nextHeartBeatIntervalMillis * (100 + heartBeatIncreasePercentage)) / 100,
+ maxHeartBeatIntervalMillis);
+ success = this.heartBeatIntervalMillis.compareAndSet(nextHeartBeatIntervalMillis, newHeartBeatIntervalMillis);
+ } else {
+ success = true;
+ }
+ }
+ return nextHeartBeatIntervalMillis;
+ }
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/Ticker.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/Ticker.java
new file mode 100644
index 00000000..26664a33
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/core/internal/blueprint/Ticker.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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.core.internal.blueprint;
+
+
+/**
+ * {@link Ticker} provides a heartbeat interface for tracking unanticipated delays. The heartbeat is configurable using
+ * a {@link HeartBeatPolicy}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of this interface must be thread safe.
+ *
+ */
+public interface Ticker {
+
+ /**
+ * Cancel this Ticker.
+ *
+ * @return <code>true</code> if and only this Ticker has ticked at least once
+ */
+ boolean cancel();
+
+ /**
+ * {@link HeartBeatPolicy} is an interface for configuring heartbeat intervals.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of this interface should be thread safe to avoid potential abuse.
+ */
+ public static interface HeartBeatPolicy {
+
+ /**
+ * Return the heartbeat interval and update the next interval according to the policy.
+ *
+ * @return the heartbeat interval in milliseconds
+ */
+ long getNextHeartBeatIntervalMillis();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/diagnostics/KernelLogEvents.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/diagnostics/KernelLogEvents.java
new file mode 100644
index 00000000..fd0503aa
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/diagnostics/KernelLogEvents.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.diagnostics;
+
+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 subsystem.
+ *
+ * <strong>Concurrent Semantics</strong><br/>
+ *
+ * Implementation is immutable.
+ *
+ */
+public enum KernelLogEvents implements LogEvent {
+ KERNEL_STARTING(1, Level.INFO), //
+ KERNEL_STARTED(2, Level.INFO), //
+ KERNEL_START_FAILED(3, Level.ERROR), //
+ KERNEL_START_TIMED_OUT(4, Level.ERROR), //
+ KERNEL_PLAN_ARGUMENTS_INCORRECT(5, Level.WARNING), //
+
+ SHUTDOWN_INITIATED(10, Level.INFO), //
+ IMMEDIATE_SHUTDOWN_INITIATED(11, Level.INFO), //
+
+ APPLICATION_CONTEXT_DEPENDENCY_DELAYED(100, Level.WARNING), //
+ APPLICATION_CONTEXT_DEPENDENCY_SATISFIED(101, Level.INFO), //
+ APPLICATION_CONTEXT_DEPENDENCY_TIMED_OUT(102, Level.ERROR), //
+
+ OVF_CONFIGURATION_FILE_DOES_NOT_EXIST(200, Level.WARNING), //
+ OVF_READ_ERROR(201, Level.ERROR);
+
+ private static final String PREFIX = "KE";
+
+ private final LogEventDelegate delegate;
+
+ private KernelLogEvents(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.core/src/main/java/org/eclipse/virgo/kernel/serviceability/Assert.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/Assert.java
new file mode 100644
index 00000000..53576942
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/Assert.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * 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.serviceability;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * A set of useful assertions based on those provided by the Spring Framework's Assert class.
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This class is thread safe.
+ *
+ * @see org.springframework.util.Assert
+ */
+public final class Assert {
+
+ /**
+ * A <code>FatalAssertionException</code> is thrown when an assertion failure occurs and will result in a dump being
+ * generated.
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This class is <strong>thread-safe</strong>.
+ *
+ */
+ final public static class FatalAssertionException extends RuntimeException {
+
+ private static final long serialVersionUID = -4633344457818398425L;
+
+ /**
+ * Creates a new FatalAssertionException with the supplied message
+ *
+ * @param message The exception message
+ */
+ public FatalAssertionException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Assert a boolean expression, throwing a <code>FatalAssertionException</code> if the test result is
+ * <code>false</code>.
+ *
+ * <pre class="code">
+ * Assert.isTrue(i &gt; 0, &quot;The value must be greater than zero&quot;);
+ * </pre>
+ *
+ * @param expression a boolean expression
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if expression is <code>false</code>
+ */
+ public static void isTrue(boolean expression, String message, Object... inserts) {
+ if (!expression) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert a boolean expression, throwing a <code>FatalAssertionException</code> if the test result is
+ * <code>true</code>.
+ *
+ * <pre class="code">
+ * Assert.isFalse(state.isBroken(), &quot;The state is broken&quot;);
+ * </pre>
+ *
+ * @param expression a boolean expression
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if expression is <code>false</code>
+ */
+ public static void isFalse(boolean expression, String message, Object... inserts) {
+ if (expression) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert that an object is <code>null</code>.
+ *
+ * <pre class="code">
+ * Assert.isNull(value, &quot;The value must be null&quot;);
+ * </pre>
+ *
+ * @param object the object to check
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if the object is not <code>null</code>
+ */
+ public static void isNull(Object object, String message, Object... inserts) {
+ if (object != null) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert that an object is not <code>null</code>.
+ *
+ * <pre class="code">
+ * Assert.notNull(clazz, &quot;The class must not be null&quot;);
+ * </pre>
+ *
+ * @param object the object to check
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if the object is <code>null</code>
+ */
+ public static void notNull(Object object, String message, Object... inserts) {
+ if (object == null) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert that the given String is not empty; that is, it must not be <code>null</code> and not the empty String.
+ *
+ * <pre class="code">
+ * Assert.hasLength(name, &quot;Name must not be empty&quot;);
+ * </pre>
+ *
+ * @param text the String to check
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @see org.eclipse.virgo.util.common.StringUtils#hasLength(String)
+ */
+ public static void hasLength(String text, String message, Object... inserts) {
+ if (text == null || text.length() == 0) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert that an array has elements; that is, it must not be <code>null</code> and must have at least one element.
+ *
+ * <pre class="code">
+ * Assert.notEmpty(array, &quot;The array must have elements&quot;);
+ * </pre>
+ *
+ * @param array the array to check
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws IllegalArgumentException if the object array is <code>null</code> or has no elements
+ */
+ public static void notEmpty(Object[] array, String message, Object... inserts) {
+ if (array == null || array.length == 0) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert that a collection has elements; that is, it must not be <code>null</code> and must have at least one
+ * element.
+ *
+ * <pre class="code">
+ * Assert.notEmpty(collection, &quot;Collection must have elements&quot;);
+ * </pre>
+ * @param <T> Element type of collection
+ *
+ * @param collection the collection to check
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if the collection is <code>null</code> or has no elements
+ */
+ public static <T> void notEmpty(Collection<T> collection, String message, Object... inserts) {
+ if (collection == null || collection.isEmpty()) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert that a Map has entries; that is, it must not be <code>null</code> and must have at least one entry.
+ *
+ * <pre class="code">
+ * Assert.notEmpty(map, &quot;Map must have entries&quot;);
+ * </pre>
+ * @param <K> Key type of map
+ * @param <V> Value type of map
+ *
+ * @param map the map to check
+ * @param message the exception message to use if the assertion fails
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if the map is <code>null</code> or has no entries
+ */
+ public static <K, V> void notEmpty(Map<K, V> map, String message, Object... inserts) {
+ if (map == null || map.isEmpty()) {
+ throw new FatalAssertionException(String.format(message, inserts));
+ }
+ }
+
+ /**
+ * Assert that the provided object is a non-null instance of the provided class.
+ *
+ * <pre class="code">
+ * Assert.instanceOf(Foo.class, foo);
+ * </pre>
+ * @param <T> Type generic
+ *
+ * @param type the type to check against
+ * @param obj the object to check
+ * @param message a message which will be prepended to the message produced by the function itself, and which may be
+ * used to provide context. It should normally end in a ": " or ". " so that the function generate message
+ * looks ok when prepended to it.
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if the object is not an instance of clazz
+ * @see Class#isInstance
+ */
+ public static <T> void isInstanceOf(Class<T> type, Object obj, String message, Object... inserts) {
+ notNull(type, "The type to check against must not be null");
+ if (!type.isInstance(obj)) {
+ throw new FatalAssertionException(String.format(message, inserts) + "Object of class [" + (obj != null ? obj.getClass().getName() : "null")
+ + "] must be an instance of " + type);
+ }
+ }
+
+ /**
+ * Assert that <code>superType.isAssignableFrom(subType)</code> is <code>true</code>.
+ *
+ * <pre class="code">
+ * Assert.isAssignable(Number.class, myClass);
+ * </pre>
+ * @param <T> SuperType
+ * @param <U> SubType
+ *
+ * @param superType the super type to check against
+ * @param subType the sub type to check
+ * @param message a message which will be prepended to the message produced by the function itself, and which may be
+ * used to provide context. It should normally end in a ": " or ". " so that the function generate message
+ * looks ok when prepended to it.
+ * @param inserts any inserts to include if the message is a format string.
+ * @throws FatalAssertionException if the classes are not assignable
+ */
+ public static <T, U> void isAssignable(Class<T> superType, Class<U> subType, String message, Object... inserts) {
+ notNull(superType, "Type to check against must not be null");
+ if (subType == null || !superType.isAssignableFrom(subType)) {
+ throw new FatalAssertionException(String.format(message, inserts) + subType + " is not assignable to " + superType);
+ }
+ }
+
+ /*
+ * Prevent instantiation - Java does not allow final abstract classes.
+ */
+ private Assert() {
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/FatalServerException.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/FatalServerException.java
new file mode 100644
index 00000000..3230e409
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/FatalServerException.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.serviceability;
+
+// TODO This exception doesn't cause a crash
+/**
+ * Fatal server exceptions are thrown when a severe error is detected in the
+ * Server which requires the Server to crash after generating diagnostics. This
+ * class is thread safe.
+ *
+ * Subsystems should throw their own specific subclasses.
+ *
+ */
+abstract public class FatalServerException extends RuntimeException {
+
+ /**
+ * Stable serial UID.
+ */
+ private static final long serialVersionUID = -4396605664802060768L;
+
+ /**
+ * An aspect will do FFDC when this exception, or subclasses of this
+ * exception, is thrown.
+ *
+ * @param message an English description of the error
+ */
+ public FatalServerException(String message) {
+ super(message);
+ }
+
+ public FatalServerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/LogEventDelegate.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/LogEventDelegate.java
new file mode 100644
index 00000000..3ed3888a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/LogEventDelegate.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.serviceability;
+
+import org.eclipse.virgo.medic.eventlog.Level;
+import org.eclipse.virgo.medic.eventlog.LogEvent;
+
+public class LogEventDelegate implements LogEvent {
+
+ private final String prefix;
+
+ private final int code;
+
+ private final Level level;
+
+ public LogEventDelegate(String prefix, int code, Level level) {
+ super();
+ this.prefix = prefix;
+ this.code = code;
+ this.level = level;
+ }
+
+ public String getEventCode() {
+ return String.format("%s%04d%1.1s", this.prefix, this.code, this.level);
+ }
+
+ public Level getLevel() {
+ return this.level;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/NonNull.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/NonNull.java
new file mode 100644
index 00000000..15f0be52
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/NonNull.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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.serviceability;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * NonNull is an annotation to automate the insert of a non-null assertion check on a method parameter. The method
+ * taking the annotated parameter(s) is advised by an aspect to inject the assertion check.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This annotation is thread safe.
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+@Documented()
+public @interface NonNull {
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/DumpCoordinator.aj b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/DumpCoordinator.aj
new file mode 100644
index 00000000..fb6f6e74
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/DumpCoordinator.aj
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.serviceability.dump;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.virgo.medic.dump.DumpGenerator;
+
+/**
+ * Advises throws of {@link RuntimeException} and triggers {@link DumpGenerator#generateDump(String,Throwable...) a dump}.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public final aspect DumpCoordinator {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private volatile DumpGenerator dumpGenerator;
+
+ private final Object monitor = new Object();
+
+ pointcut serviceability() : within(org.eclipse.virgo.kernel.serviceability..*);
+
+ pointcut dumpCandidate() : (execution(* *(..)) || initialization(*.new(..))) && !serviceability();
+
+ after() throwing(RuntimeException e) : dumpCandidate() {
+ if (!FFDCExceptionState.seen(e)) {
+ FFDCExceptionState.record(e);
+
+ synchronized (this.monitor) {
+ if (this.dumpGenerator != null) {
+ this.dumpGenerator.generateDump("error", e);
+ } else {
+ logger.warn("No DumpGenerator available");
+ }
+ }
+ }
+ }
+
+ // TODO Consider using a ServiceTracker
+ public void setBundleContext(BundleContext bundleContext) {
+ ServiceReference serviceReference = bundleContext.getServiceReference(DumpGenerator.class.getName());
+ if (serviceReference != null) {
+ DumpGenerator dumpGenerator = (DumpGenerator) bundleContext.getService(serviceReference);
+ if (dumpGenerator != null) {
+ setDumpGenerator(dumpGenerator);
+ } else {
+ throw new IllegalStateException("DumpGenerator not available in the ServiceRegistry");
+ }
+ }
+ }
+
+ public void setDumpGenerator(DumpGenerator dumpGenerator) {
+ synchronized (this.monitor) {
+ this.dumpGenerator = dumpGenerator;
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionState.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionState.java
new file mode 100644
index 00000000..c81d467e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionState.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.serviceability.dump;
+
+/**
+ * Maintains state about which {@link Throwable} was last seen for the current thread.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * State is thread local.
+ *
+ */
+final class FFDCExceptionState {
+
+ private static final State STATE = new State();
+
+ /**
+ * Record that the supplied {@link Throwable} has been seen.
+ *
+ * @param t the <code>Throwable</code>.
+ */
+ public static void record(Throwable t) {
+ STATE.set(t);
+ }
+
+ /**
+ * Query whether the supplied {@link Throwable} or one of its causes has been seen.
+ *
+ * @param t the <code>Throwable</code>
+ * @return <code>true</code> if the <code>Throwable</code> has been seen, otherwise <code>false</code>.
+ */
+ public static boolean seen(Throwable t) {
+ boolean seen = false;
+ Throwable s = t;
+ do {
+ if (s.equals(STATE.get())) {
+ seen = true;
+ break;
+ }
+ s = s.getCause();
+ } while (s != null);
+ return seen;
+ }
+
+ private static class State extends ThreadLocal<Throwable> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override public String toString() {
+ return String.format("FFDC Exception State [lastSeen = '" + get() + "']");
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcer.aj b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcer.aj
new file mode 100644
index 00000000..5dc94533
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcer.aj
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.serviceability.enforcement;
+
+import org.aspectj.lang.annotation.SuppressAjWarnings;
+import org.eclipse.virgo.kernel.serviceability.Assert;
+import org.eclipse.virgo.kernel.serviceability.NonNull;
+
+
+/**
+ * Aspect that enforces that parameters annotated with {@link NonNull} are, in fact, non null.
+ * <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public final aspect NonNullAssertionEnforcer {
+
+ pointcut serviceability() : within(org.eclipse.virgo.kernel.serviceability..*);
+
+ pointcut executingOperationWithNonNullFirstParameter(Object obj) :
+ !serviceability() &&
+ (execution(* *(@NonNull (*), ..)) || preinitialization(*.new(@NonNull (*), ..))) && args(obj, ..) ;
+
+ pointcut executingOperationWithNonNullSecondParameter(Object obj) :
+ !serviceability() &&
+ (execution(* *(*, @NonNull (*), ..)) || preinitialization(*.new(*, @NonNull (*), ..))) && args(*, obj, ..);
+
+ pointcut executingOperationWithNonNullThirdParameter(Object obj) :
+ !serviceability() &&
+ (execution(* *(*, *, @NonNull (*), ..)) || preinitialization(*.new(*, *, @NonNull (*), ..))) && args(*, * , obj, ..);
+
+ pointcut executingOperationWithNonNullFourthParameter(Object obj) :
+ !serviceability() &&
+ (execution(* *(*, *, *, @NonNull (*), ..)) || preinitialization(*.new(*, *, *, @NonNull (*), ..))) && args(*, *, *, obj, ..);
+
+ pointcut executingOperationWithNonNullFifthParameter(Object obj) :
+ !serviceability() &&
+ (execution(* *(*, *, *, *, @NonNull (*), ..)) || preinitialization(*.new(*, *, *, *, @NonNull (*), ..))) && args(*, *, *, *, obj, ..);
+
+ before(Object argValue) : executingOperationWithNonNullFirstParameter(argValue) {
+ Assert.notNull(argValue, "Argument [1] cannot be null");
+ }
+
+ before(Object argValue) : executingOperationWithNonNullSecondParameter(argValue) {
+ Assert.notNull(argValue, "Argument [2] cannot be null");
+ }
+
+ before(Object argValue) : executingOperationWithNonNullThirdParameter(argValue) {
+ Assert.notNull(argValue, "Argument [3] cannot be null");
+ }
+
+ @SuppressAjWarnings({"adviceDidNotMatch"})
+ before(Object argValue) : executingOperationWithNonNullFourthParameter(argValue) {
+ Assert.notNull(argValue, "Argument [4] cannot be null");
+ }
+
+ @SuppressAjWarnings({"adviceDidNotMatch"})
+ before(Object argValue) : executingOperationWithNonNullFifthParameter(argValue) {
+ Assert.notNull(argValue, "Argument [5] cannot be null");
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/Scope.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/Scope.java
new file mode 100644
index 00000000..1949b17a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/Scope.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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.shim.scope;
+
+/**
+ * {@link Scope} defines a collection of bundles, packages, and services. There is a global scope as well as more local scopes such as those used to contain
+ * multi-bundle applications.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of this interface must be thread safe.
+ *
+ */
+public interface Scope {
+
+ public static final String PROPERTY_SERVICE_SCOPE = "com.springsource.service.scope";
+
+ public static final String SCOPE_ID_GLOBAL = "global";
+
+ public static final String SCOPE_ID_APP = "app";
+
+ /**
+ * Return <code>true</code> if and only if this scope is global.
+ *
+ * @return <code>true</code> if and only if this scope is global
+ */
+ boolean isGlobal();
+
+ /**
+ * Return the name of this scope or <code>null</code> if this scope is global.
+ *
+ * @return the name of this scope or <code>null</code> if this scope is global
+ */
+ String getScopeName();
+
+ /**
+ * Get the value of the scope property with the given name or <code>null</code> if the scope has no such property.
+ *
+ * @param propertyName the name of the property
+ * @return the value of the property or <code>null</code> if the scope has no such property
+ */
+ Object getProperty(String propertyName);
+
+ /**
+ * Set the value of the scope property with the given name to the given value.
+ *
+ * @param propertyName the name of the property
+ * @param propertyValue the value of the property
+ */
+ void setProperty(String propertyName, Object propertyValue);
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/ScopeFactory.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/ScopeFactory.java
new file mode 100644
index 00000000..867c5a4d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/ScopeFactory.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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.shim.scope;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Creates {@link Scope} instances for {@link ServiceReference ServiceReferences} and for lookups. <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of this interface must be thread safe.
+ *
+ */
+public interface ScopeFactory {
+
+ /**
+ * Get the {@link Scope} containing the given {@link Bundle}.
+ *
+ * @param bundle the <code>Bundle</code> whose scope is required
+ * @return the <code>Scope</code> containing the given bundle
+ */
+ Scope getBundleScope(Bundle bundle);
+
+ /**
+ * Get the global {@link Scope}.
+ *
+ * @return the global <code>Scope</code>
+ */
+ Scope getGlobalScope();
+
+ /**
+ * Gets the {@link Scope} under which the referenced service is published.
+ * @param ref service reference
+ * @return the scope
+ */
+ Scope getServiceScope(ServiceReference ref);
+
+ /**
+ * Get the {@link Scope} for the given application scope name.
+ *
+ * @param applicationScopeName the name of the scope
+ * @return the {@link Scope} with the given name
+ */
+ Scope getApplicationScope(String applicationScopeName);
+
+ /**
+ * Destroy the given application {@link Scope}. Existing <code>Scope</code> instances equivalent to the given
+ * <code>Scope</code> will continue to exist and share properties, but calls to get a <code>Scope</code> with the
+ * same application scope name as the given <code>Scope</code> will produce a new <code>Scope</code> with a distinct
+ * collection of properties. Effectively, this method delimits a 'generation' of an application scope.
+ *
+ * @param applicationScope the application <code>Scope</code> to be destroyed.
+ */
+ void destroyApplicationScope(Scope applicationScope);
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/internal/StandardScopeFactory.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/internal/StandardScopeFactory.java
new file mode 100644
index 00000000..b62e6727
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/scope/internal/StandardScopeFactory.java
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ * 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.shim.scope.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.virgo.kernel.shim.scope.Scope;
+import org.eclipse.virgo.kernel.shim.scope.ScopeFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+
+
+/**
+ * Creates {@link Scope} instances for {@link ServiceReference ServiceReferences} and for lookups.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public final class StandardScopeFactory implements ScopeFactory {
+
+ private static final String PROPERTY_BEAN_NAME = "org.springframework.osgi.bean.name";
+
+ /*
+ * Share application scope properties between equivalent application scope instances
+ */
+ private final Map<AppScope, ConcurrentHashMap<String, Object>> properties = new HashMap<AppScope, ConcurrentHashMap<String, Object>>();
+
+ public StandardScopeFactory() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Scope getBundleScope(Bundle bundle) {
+ return isBundleScoped(bundle) ? createApplicationScope(bundle) : GlobalScope.INSTANCE;
+
+ }
+
+ /**
+ * @param bundle
+ * @return
+ */
+ private Scope createApplicationScope(Bundle bundle) {
+ return getApplicationScope(getScopeName(bundle));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Scope getGlobalScope() {
+ return GlobalScope.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Scope getServiceScope(ServiceReference ref) {
+ return Scope.SCOPE_ID_APP.equals(getScopeIdentifier(ref)) ? getBundleScope(ref.getBundle()) : getGlobalScope();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Scope getApplicationScope(String applicationScopeName) {
+ synchronized (this.properties) {
+ AppScope appScope = new AppScope(applicationScopeName);
+ ConcurrentHashMap<String, Object> props = this.properties.get(appScope);
+ if (props == null) {
+ props = new ConcurrentHashMap<String, Object>();
+ this.properties.put(appScope, props);
+ }
+ appScope.setProperties(props);
+
+ return appScope;
+ }
+ }
+
+ private static String getScopeIdentifier(ServiceReference ref) {
+ String serviceScope = (String) ref.getProperty(Scope.PROPERTY_SERVICE_SCOPE);
+ if (serviceScope == null) {
+ String beanName = (String) ref.getProperty(PROPERTY_BEAN_NAME);
+ if (beanName == null) {
+ serviceScope = Scope.SCOPE_ID_GLOBAL;
+ } else {
+ if (isBundleScoped(ref.getBundle())) {
+ serviceScope = Scope.SCOPE_ID_APP;
+ } else {
+ serviceScope = Scope.SCOPE_ID_GLOBAL;
+ }
+ }
+ }
+ return serviceScope;
+ }
+
+ private static boolean isBundleScoped(Bundle bundle) {
+ // TODO: reinstate return OsgiFrameworkUtils.getScopeName(bundle) != null;
+ return getScopeName(bundle) != null;
+ }
+
+ private static String getScopeName(Bundle bundle) {
+ // TODO: use OFUtils instead when in proper location
+ return (String) bundle.getHeaders().get("Module-Scope");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void destroyApplicationScope(Scope applicationScope) {
+ // TODO: reinstate Assert.isTrue(applicationScope instanceof AppScope, "wrong scope type");
+ AppScope appScope = (AppScope) applicationScope;
+ synchronized (this.properties) {
+ this.properties.remove(appScope);
+ }
+ }
+
+ private abstract static class StandardScope implements Scope {
+
+ private volatile ConcurrentHashMap<String, Object> properties;
+
+ protected StandardScope() {
+ }
+
+ final void setProperties(ConcurrentHashMap<String, Object> properties) {
+ // TODO: reinstate Assert.isNull(this.properties, "properties can only be set once");
+ this.properties = properties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final Object getProperty(String propertyName) {
+ // TODO: reinstate Assert.isTrue(this.properties != null, "properties not set");
+ return this.properties.get(propertyName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final void setProperty(String propertyName, Object propertyValue) {
+ // TODO: reinstate Assert.isTrue(this.properties != null, "properties not set");
+ this.properties.put(propertyName, propertyValue);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ StandardScope other = (StandardScope) obj;
+ /*
+ * Instances that have not had their properties set compare equal (unless overridden by subclasses).
+ * Instances that have had their properties set must use the same properties object reference to compare
+ * equal.
+ */
+ if (properties == null || other.properties == null) {
+ return true;
+ } else if (properties != other.properties) {
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ private static class GlobalScope extends StandardScope {
+
+ static GlobalScope INSTANCE = new GlobalScope();
+
+ private GlobalScope() {
+ setProperties(new ConcurrentHashMap<String, Object>());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return 316;
+ }
+
+ public boolean equals(Object other) {
+ return other == this || other instanceof GlobalScope;
+ }
+
+ public String toString() {
+ return Scope.SCOPE_ID_GLOBAL;
+ }
+
+ public boolean isGlobal() {
+ return true;
+ }
+
+ public String getScopeName() {
+ // The global scope does not have a name.
+ return null;
+ }
+ }
+
+ private static class AppScope extends StandardScope {
+
+ private final String scopeName;
+
+ public AppScope(String scopeName) {
+ this.scopeName = scopeName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((scopeName == null) ? 0 : scopeName.hashCode());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AppScope other = (AppScope) obj;
+ if (scopeName == null) {
+ if (other.scopeName != null) {
+ return false;
+ }
+ } else if (!scopeName.equals(other.scopeName)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ return Scope.SCOPE_ID_APP + ":" + this.scopeName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isGlobal() {
+ return false;
+ }
+
+ public String getScopeName() {
+ return this.scopeName;
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/TracingService.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/TracingService.java
new file mode 100644
index 00000000..a987aa62
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/TracingService.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.shim.serviceability;
+
+/**
+ * <p>
+ * The Platform's tracing service.
+ * <p/>
+ * <p>
+ * An instance of this interface is available from the OSGi service registry.
+ * </p>
+ * <p>
+ * <strong>Concurrent Semantics</strong><br />
+ * Implementations <strong>must</strong> be thread safe.
+ * </p>
+ *
+ */
+public interface TracingService {
+
+ /**
+ * Informs the tracing service that the calling thread is within the scope of the application identified by
+ * <code>applicationName</code>. This setting can be cleared, e.g. because the calling thread is no longer in the
+ * scope of an application, by calling this method with <code>null</code>.
+ *
+ * @param applicationName The name of the application that is in scope on the calling thread.
+ */
+ void setCurrentApplicationName(String applicationName);
+
+ /**
+ * Returns the name of the application that is currently associated with the current thread
+ *
+ * @return The name of the application associated with the thread.
+ */
+ String getCurrentApplicationName();
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/internal/Slf4jTracingService.java b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/internal/Slf4jTracingService.java
new file mode 100644
index 00000000..e4ca11b4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/java/org/eclipse/virgo/kernel/shim/serviceability/internal/Slf4jTracingService.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.shim.serviceability.internal;
+
+import org.eclipse.virgo.kernel.shim.serviceability.TracingService;
+import org.slf4j.MDC;
+
+
+public final class Slf4jTracingService implements TracingService {
+
+ public static final String APPLICATION_NAME = "applicationName";
+
+ public String getCurrentApplicationName() {
+ return MDC.get(APPLICATION_NAME);
+ }
+
+ public void setCurrentApplicationName(String applicationName) {
+ MDC.put(APPLICATION_NAME, applicationName);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/main/resources/EventLogMessages.properties b/org.eclipse.virgo.kernel.core/src/main/resources/EventLogMessages.properties
new file mode 100644
index 00000000..45e2540b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/main/resources/EventLogMessages.properties
@@ -0,0 +1,15 @@
+KE0001I = Kernel starting.
+KE0002I = Kernel started.
+KE0003E = Kernel failed to start.
+KE0004E = Kernel failed to start within {} seconds.
+KE0005W = Option -plan requires one or two arguments but {} were provided: '{}'.
+
+KE0010I = Shutdown initiated.
+KE0011I = Immediate shutdown initiated.
+
+KE0100W = Reference '{}' in bundle '{}' version '{}' is waiting for service with filter '{}'.
+KE0101I = Reference '{}' in bundle '{}' version '{}' was satisfied by service with filter '{}'.
+KE0102E = Reference '{}' in bundle '{}' version '{}' timed out waiting for service with filter '{}'.
+
+KE0200W = OVF configuration file '{}' does not exist.
+KE0201E = Error reading OVF configuration file '{}'.
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfiguration.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfiguration.java
new file mode 100644
index 00000000..2d09a67f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfiguration.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.service.cm.Configuration;
+
+public class StubConfiguration implements Configuration {
+
+ private Hashtable properties = new Hashtable();
+
+ public void delete() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getBundleLocation() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getFactoryPid() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPid() {
+ throw new UnsupportedOperationException();
+ }
+
+ @SuppressWarnings("unchecked")
+ public Dictionary getProperties() {
+ Hashtable propertiesCopy = new Hashtable();
+ propertiesCopy.putAll(this.properties);
+ return propertiesCopy;
+ }
+
+ public void setBundleLocation(String arg0) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void update() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void update(Dictionary dictionary) throws IOException {
+ this.properties = (Hashtable)dictionary;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfigurationAdmin.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfigurationAdmin.java
new file mode 100644
index 00000000..ece41256
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/StubConfigurationAdmin.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;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+
+public class StubConfigurationAdmin implements ConfigurationAdmin {
+
+ private final Map<String, Configuration> configurations = new HashMap<String, Configuration>();
+
+ public Configuration createFactoryConfiguration(String arg0) throws IOException {
+ return createFactoryConfiguration(arg0, null);
+ }
+
+ public Configuration createFactoryConfiguration(String arg0, String arg1) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Configuration getConfiguration(String arg0) throws IOException {
+ return getConfiguration(arg0, null);
+ }
+
+ public Configuration getConfiguration(String pid, String location) throws IOException {
+ Configuration configuration = this.configurations.get(pid);
+ if (configuration == null) {
+ configuration = new StubConfiguration();
+ configurations.put(pid, configuration);
+ }
+ return configuration;
+ }
+
+ public Configuration[] listConfigurations(String arg0) throws IOException, InvalidSyntaxException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisherTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisherTests.java
new file mode 100644
index 00000000..5904d1a8
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ConfigurationPublisherTests.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+import org.eclipse.virgo.kernel.StubConfigurationAdmin;
+import org.eclipse.virgo.kernel.config.internal.ConfigurationPublisher;
+import org.eclipse.virgo.kernel.config.internal.PropertiesSource;
+import org.junit.Test;
+import org.osgi.service.cm.Configuration;
+
+
+/**
+ */
+public class ConfigurationPublisherTests {
+
+ @Test
+ public void testSingleSource() throws IOException {
+ StubPropertiesSource source = new StubPropertiesSource();
+
+ String pid = "single";
+
+ Properties p = new Properties();
+ p.setProperty("foo", "bar");
+
+ source.configurationProperties.put(pid, p);
+
+ StubConfigurationAdmin configAdmin = new StubConfigurationAdmin();
+
+ ConfigurationPublisher publisher = new ConfigurationPublisher(configAdmin, source);
+ publisher.publishConfigurations();
+
+ Configuration configuration = configAdmin.getConfiguration(pid);
+ assertConfigurationEquals(configuration, p);
+
+ }
+
+ @Test
+ public void testTwoSources() throws Exception {
+ StubPropertiesSource one = new StubPropertiesSource();
+ StubPropertiesSource two = new StubPropertiesSource();
+
+ // setup one
+ String pidOne = "one";
+
+ Properties propertiesOne = new Properties();
+ propertiesOne.setProperty("foo", "bar");
+
+ one.configurationProperties.put(pidOne, propertiesOne);
+
+ // setup two
+ String pidTwo = "two";
+
+ Properties propertiesTwo = new Properties();
+ propertiesTwo.setProperty("bar", "baz");
+
+ two.configurationProperties.put(pidTwo, propertiesTwo);
+
+ StubConfigurationAdmin configAdmin = new StubConfigurationAdmin();
+
+ ConfigurationPublisher publisher = new ConfigurationPublisher(configAdmin, one, two);
+ publisher.publishConfigurations();
+
+ Configuration configuration = configAdmin.getConfiguration(pidOne);
+ assertConfigurationEquals(configuration, propertiesOne);
+
+ configuration = configAdmin.getConfiguration(pidTwo);
+ assertConfigurationEquals(configuration, propertiesTwo);
+
+ }
+
+ @Test
+ public void testMultiSourceMerge() throws Exception {
+ StubPropertiesSource one = new StubPropertiesSource();
+ StubPropertiesSource two = new StubPropertiesSource();
+
+ // setup one
+ String pidOne = "one";
+
+ Properties propertiesOne = new Properties();
+ propertiesOne.setProperty("foo", "bar");
+ propertiesOne.setProperty("bar", "baz");
+
+ one.configurationProperties.put(pidOne, propertiesOne);
+
+ // setup two
+ String pidTwo = pidOne;
+
+ Properties propertiesTwo = new Properties();
+ propertiesTwo.setProperty("bar", "boo");
+ propertiesTwo.setProperty("boo", "bof");
+
+ two.configurationProperties.put(pidTwo, propertiesTwo);
+
+ StubConfigurationAdmin configAdmin = new StubConfigurationAdmin();
+
+ ConfigurationPublisher publisher = new ConfigurationPublisher(configAdmin, one, two);
+ publisher.publishConfigurations();
+
+ Configuration configuration = configAdmin.getConfiguration(pidOne);
+
+ assertEquals("bar", configuration.getProperties().get("foo"));
+ assertEquals("boo", configuration.getProperties().get("bar"));
+ assertEquals("bof", configuration.getProperties().get("boo"));
+ }
+
+ private void assertConfigurationEquals(Configuration configuration, Properties properties) {
+ for (String s : properties.stringPropertyNames()) {
+ assertEquals(properties.getProperty(s), configuration.getProperties().get(s));
+ }
+ }
+
+ private static class StubPropertiesSource implements PropertiesSource {
+
+ private final Map<String, Properties> configurationProperties = new TreeMap<String, Properties>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Properties> getConfigurationProperties() {
+ return this.configurationProperties;
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSourceTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSourceTests.java
new file mode 100644
index 00000000..5b361493
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationPropertiesSourceTests.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+import java.util.Properties;
+
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.config.internal.KernelConfiguration;
+import org.eclipse.virgo.kernel.config.internal.KernelConfigurationPropertiesSource;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+
+
+
+/**
+ */
+public class KernelConfigurationPropertiesSourceTests {
+
+ @Test
+ public void testGetProperties() {
+ StubBundleContext context = new StubBundleContext();
+ context.addProperty(KernelConfiguration.PROPERTY_KERNEL_HOME, "target/home");
+
+ KernelConfiguration configuration = new KernelConfiguration(context);
+
+ KernelConfigurationPropertiesSource source = new KernelConfigurationPropertiesSource(configuration);
+
+ Map<String, Properties> configurationProperties = source.getConfigurationProperties();
+ Properties properties = configurationProperties.get(KernelConfigurationPropertiesSource.KERNEL_CONFIGURATION_PID);
+ assertNotNull(properties);
+ assertEquals(configuration.getDomain(), properties.getProperty(KernelConfigurationPropertiesSource.PROPERTY_DOMAIN));
+ assertEquals(configuration.getHomeDirectory().getAbsolutePath(), properties.getProperty(KernelConfigurationPropertiesSource.PROPERTY_HOME_DIRECTORY));
+ assertEquals(configuration.getWorkDirectory().getAbsolutePath(), properties.getProperty(KernelConfigurationPropertiesSource.PROPERTY_WORK_DIRECTORY));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationTests.java
new file mode 100644
index 00000000..cbc667cf
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/KernelConfigurationTests.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.config.internal.KernelConfiguration;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+
+
+/**
+ */
+public class KernelConfigurationTests {
+
+ @Test
+ public void testCreateMinimalKernelConfiguration() {
+ StubBundleContext context = new StubBundleContext();
+ context.addProperty(KernelConfiguration.PROPERTY_KERNEL_HOME, "target");
+
+ KernelConfiguration configuration = new KernelConfiguration(context);
+ assertEquals(new File("target"), configuration.getHomeDirectory());
+ assertNotNull(configuration.getWorkDirectory());
+ assertNotNull(configuration.getConfigDirectories());
+ assertEquals(1, configuration.getConfigDirectories().length);
+ assertNotNull(configuration.getDomain());
+ }
+
+ @Test
+ public void testCustomConfiguration() {
+ StubBundleContext context = new StubBundleContext();
+ context.addProperty(KernelConfiguration.PROPERTY_KERNEL_HOME, "target");
+ context.addProperty(KernelConfiguration.PROPERTY_KERNEL_DOMAIN, "my.domain");
+ context.addProperty(KernelConfiguration.PROPERTY_KERNEL_CONFIG, "foo,bar");
+
+ KernelConfiguration configuration = new KernelConfiguration(context);
+ assertEquals(new File("target"), configuration.getHomeDirectory());
+ assertNotNull(configuration.getWorkDirectory());
+ assertNotNull(configuration.getConfigDirectories());
+ assertEquals(2, configuration.getConfigDirectories().length);
+ assertEquals("my.domain", configuration.getDomain());
+ }
+
+ @Test(expected=IllegalStateException.class)
+ public void testMissingKernelHomeProperty() {
+ new KernelConfiguration(new StubBundleContext());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSourceTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSourceTests.java
new file mode 100644
index 00000000..cde779fd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/UserConfigurationPropertiesSourceTests.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.config.internal;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Properties;
+
+import org.eclipse.virgo.kernel.config.internal.UserConfigurationPropertiesSource;
+import org.junit.Test;
+
+
+import static org.junit.Assert.*;
+
+
+/**
+ */
+public class UserConfigurationPropertiesSourceTests {
+
+ @Test
+ public void testReadUserConfiguration() {
+ File[] dirs = new File[]{
+ new File("src/test/resources/" + getClass().getSimpleName())
+ };
+
+ UserConfigurationPropertiesSource source = new UserConfigurationPropertiesSource(dirs);
+ Map<String, Properties> properties = source.getConfigurationProperties();
+
+ Properties one = properties.get("one");
+ Properties two = properties.get("two");
+ assertNotNull(one);
+ assertNotNull(two);
+ assertEquals("bar", one.getProperty("foo"));
+ assertEquals("baz", two.getProperty("bar"));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSourceTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSourceTests.java
new file mode 100644
index 00000000..c59e73f0
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/commandline/CommandLinePropertiesSourceTests.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * 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.config.internal.commandline;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.junit.Test;
+
+
+import org.eclipse.virgo.kernel.config.internal.PropertiesSource;
+import org.eclipse.virgo.kernel.config.internal.commandline.CommandLinePropertiesSource;
+import org.eclipse.virgo.medic.test.eventlog.LoggedEvent;
+import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+
+public class CommandLinePropertiesSourceTests {
+
+ private StubBundleContext bundleContext = new StubBundleContext();
+
+ private MockEventLogger eventLogger = new MockEventLogger();
+
+ @Test
+ public void defaults() {
+ PropertiesSource propertiesSource = new CommandLinePropertiesSource(this.bundleContext, this.eventLogger);
+ Map<String, Properties> configurationProperties = propertiesSource.getConfigurationProperties();
+
+ Properties properties = configurationProperties.get("org.eclipse.virgo.kernel.userregion");
+ assertNotNull(properties);
+
+ assertEquals("", properties.get("commandLineArtifacts"));
+
+ assertEquals(0, this.eventLogger.getLoggedEvents().size());
+ }
+
+ @Test
+ public void singlePlanWithVersion() {
+ this.bundleContext.addProperty("org.eclipse.virgo.osgi.launcher.unrecognizedArguments", "-plan,foo,1");
+ PropertiesSource propertiesSource = new CommandLinePropertiesSource(this.bundleContext, this.eventLogger);
+ Map<String, Properties> configurationProperties = propertiesSource.getConfigurationProperties();
+
+ Properties properties = configurationProperties.get("org.eclipse.virgo.kernel.userregion");
+ assertNotNull(properties);
+
+ assertEquals("repository:plan/foo/1", properties.get("commandLineArtifacts"));
+
+ assertEquals(0, this.eventLogger.getLoggedEvents().size());
+ }
+
+ @Test
+ public void singlePlanWithoutVersion() {
+ this.bundleContext.addProperty("org.eclipse.virgo.osgi.launcher.unrecognizedArguments", "-plan,foo");
+ PropertiesSource propertiesSource = new CommandLinePropertiesSource(this.bundleContext, this.eventLogger);
+ Map<String, Properties> configurationProperties = propertiesSource.getConfigurationProperties();
+
+ Properties properties = configurationProperties.get("org.eclipse.virgo.kernel.userregion");
+ assertNotNull(properties);
+
+ assertEquals("repository:plan/foo", properties.get("commandLineArtifacts"));
+
+ assertEquals(0, this.eventLogger.getLoggedEvents().size());
+ }
+
+ @Test
+ public void multiplePlans() {
+ this.bundleContext.addProperty("org.eclipse.virgo.osgi.launcher.unrecognizedArguments", "-plan,foo,-plan,bar,1.2.3");
+ PropertiesSource propertiesSource = new CommandLinePropertiesSource(this.bundleContext, this.eventLogger);
+ Map<String, Properties> configurationProperties = propertiesSource.getConfigurationProperties();
+
+ Properties properties = configurationProperties.get("org.eclipse.virgo.kernel.userregion");
+ assertNotNull(properties);
+
+ assertEquals("repository:plan/foo,repository:plan/bar/1.2.3", properties.get("commandLineArtifacts"));
+
+ assertEquals(0, this.eventLogger.getLoggedEvents().size());
+ }
+
+ @Test
+ public void planWithMissingArguments() {
+ this.bundleContext.addProperty("org.eclipse.virgo.osgi.launcher.unrecognizedArguments", "-plan");
+ PropertiesSource propertiesSource = new CommandLinePropertiesSource(this.bundleContext, this.eventLogger);
+ Map<String, Properties> configurationProperties = propertiesSource.getConfigurationProperties();
+
+ Properties properties = configurationProperties.get("org.eclipse.virgo.kernel.userregion");
+ assertNotNull(properties);
+
+ assertEquals("", properties.get("commandLineArtifacts"));
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(1, loggedEvents.size());
+
+ assertArrayEquals(new Object[] {0, ""}, loggedEvents.get(0).getInserts());
+ }
+
+ @Test
+ public void planWithSurplusArguments() {
+ this.bundleContext.addProperty("org.eclipse.virgo.osgi.launcher.unrecognizedArguments", "-plan,foo,bar,1.2.3");
+ PropertiesSource propertiesSource = new CommandLinePropertiesSource(this.bundleContext, this.eventLogger);
+ Map<String, Properties> configurationProperties = propertiesSource.getConfigurationProperties();
+
+ Properties properties = configurationProperties.get("org.eclipse.virgo.kernel.userregion");
+ assertNotNull(properties);
+
+ assertEquals("", properties.get("commandLineArtifacts"));
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(1, loggedEvents.size());
+
+ assertArrayEquals(new Object[] {3, "foo, bar, 1.2.3"}, loggedEvents.get(0).getInserts());
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReaderTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReaderTests.java
new file mode 100644
index 00000000..8604b3b0
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfEnvironmentPropertiesReaderTests.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.config.internal.ovf;
+
+import java.io.FileReader;
+import java.util.Properties;
+
+import org.eclipse.virgo.kernel.config.internal.ovf.OvfEnvironmentPropertiesReader;
+import org.junit.Test;
+
+
+import static org.junit.Assert.*;
+
+
+/**
+ */
+public class OvfEnvironmentPropertiesReaderTests {
+
+ @Test
+ public void testReadProperties() throws Exception {
+
+ OvfEnvironmentPropertiesReader reader = new OvfEnvironmentPropertiesReader();
+ Properties props = reader.readProperties(new FileReader("src/test/resources/ovf/environment.xml"));
+ assertEquals("bar", props.getProperty("com.myapp.foo"));
+ assertEquals("baz", props.getProperty("com.myapp.bar"));
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSourceTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSourceTests.java
new file mode 100644
index 00000000..f6e3243c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/config/internal/ovf/OvfPropertiesSourceTests.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.config.internal.ovf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.junit.Test;
+
+
+import org.eclipse.virgo.kernel.config.internal.ovf.OvfPropertiesSource;
+import org.eclipse.virgo.kernel.diagnostics.KernelLogEvents;
+import org.eclipse.virgo.medic.test.eventlog.LoggedEvent;
+import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+
+
+/**
+ */
+public class OvfPropertiesSourceTests {
+
+ @Test
+ public void testReadValidFile() {
+ MockEventLogger logger = new MockEventLogger();
+
+ StubBundleContext context = new StubBundleContext();
+ context.addProperty(OvfPropertiesSource.FRAMEWORK_PROPERTY_OVF, "src/test/resources/ovf/valid.xml");
+
+ OvfPropertiesSource source = new OvfPropertiesSource(context, logger);
+ Map<String, Properties> properties = source.getConfigurationProperties();
+ assertNotNull(properties);
+
+ Properties one = properties.get("one");
+ assertNotNull(one);
+ assertEquals("bar", one.getProperty("foo"));
+ assertEquals("baz", one.getProperty("bar"));
+
+ Properties two = properties.get("two");
+ assertNotNull(two);
+ assertEquals("quux", two.getProperty("baz"));
+
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testReadFileWithInvalidProperty() {
+ MockEventLogger logger = new MockEventLogger();
+
+ StubBundleContext context = new StubBundleContext();
+ context.addProperty(OvfPropertiesSource.FRAMEWORK_PROPERTY_OVF, "src/test/resources/ovf/invalid.xml");
+
+ OvfPropertiesSource source = new OvfPropertiesSource(context, logger);
+ source.getConfigurationProperties();
+ }
+
+ @Test
+ public void testReadNonExistentFile() {
+ MockEventLogger logger = new MockEventLogger();
+
+ StubBundleContext context = new StubBundleContext();
+ context.addProperty(OvfPropertiesSource.FRAMEWORK_PROPERTY_OVF, "src/test/resources/ovf/nonexistent.xml");
+
+ OvfPropertiesSource source = new OvfPropertiesSource(context, logger);
+ Map<String, Properties> properties = source.getConfigurationProperties();
+
+ List<LoggedEvent> loggedEvents = logger.getLoggedEvents();
+ assertEquals(1, loggedEvents.size());
+
+ LoggedEvent loggedEvent = loggedEvents.get(0);
+ assertEquals(KernelLogEvents.OVF_CONFIGURATION_FILE_DOES_NOT_EXIST.getEventCode(), loggedEvent.getCode());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/BundleStartTrackerTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/BundleStartTrackerTests.java
new file mode 100644
index 00000000..0398a61d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/BundleStartTrackerTests.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.service.event.Event;
+import org.springframework.core.task.SyncTaskExecutor;
+
+import org.eclipse.virgo.kernel.core.Signal;
+import org.eclipse.virgo.kernel.core.internal.BundleStartTracker;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+
+
+/**
+ */
+public class BundleStartTrackerTests {
+
+ @Test
+ public void startOfBundleThatIsNotPoweredBySpringDm() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.setBundleContext(bundleContext);
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+ bundle.start();
+
+ assertEquals(1, signal.successCount);
+ assertEquals(0, signal.failures.size());
+
+ assertEquals(Bundle.ACTIVE, bundle.getState());
+ }
+
+ @Test
+ public void startOfBundleThatIsPoweredBySpringDm() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(0, signal.successCount);
+ assertEquals(0, signal.failures.size());
+
+ bundle.start();
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/CREATED", properties));
+
+ assertEquals(1, signal.successCount);
+ assertEquals(0, signal.failures.size());
+ }
+
+ @Test
+ public void applicationContextCreationFailureOfBundleThatIsPoweredBySpringDm() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(0, signal.successCount);
+ assertEquals(0, signal.failures.size());
+
+ bundle.start();
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+ Exception failure = new Exception();
+ properties.put("exception", failure);
+
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/FAILURE", properties));
+
+ assertEquals(0, signal.successCount);
+ assertEquals(1, signal.failures.size());
+
+ assertTrue(signal.failures.contains(failure));
+ }
+
+ @Test
+ public void trackingOfSpringDmPoweredBundleThatAlreadyCreatedItsContainer() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/CREATED", properties));
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(1, signal.successCount);
+ assertEquals(0, signal.failures.size());
+ }
+
+ @Test
+ public void trackingOfSpringDmPoweredBundleThatHasAlreadyFailedToCreateItsApplicationContext() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+ Exception failure = new Exception();
+ properties.put("exception", failure);
+
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/FAILURE", properties));
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(0, signal.successCount);
+ assertEquals(1, signal.failures.size());
+ assertTrue(signal.failures.contains(failure));
+ }
+
+ @Test
+ public void signalIsOnlyDrivenOnceEvenWithMultipleEventsForStartOfBundleThatIsPoweredBySpringDm() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(0, signal.successCount);
+ assertEquals(0, signal.failures.size());
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/CREATED", properties));
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/CREATED", properties));
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/CREATED", properties));
+
+ assertEquals(1, signal.successCount);
+ assertEquals(0, signal.failures.size());
+ }
+
+ @Test
+ public void signalIsOnlyDrivenOnceEvenWithMultipleEventsForApplicationContextCreationFailureOfBundleThatIsPoweredBySpringDm() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(0, signal.successCount);
+ assertEquals(0, signal.failures.size());
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+ Exception failure = new Exception();
+ properties.put("exception", failure);
+
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/FAILURE", properties));
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/FAILURE", properties));
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/FAILURE", properties));
+
+ assertEquals(0, signal.successCount);
+ assertEquals(1, signal.failures.size());
+
+ assertTrue(signal.failures.contains(failure));
+ }
+
+ @Test
+ public void createdStateIsCleanedUpWhenBundleIsStopped() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.setBundleContext(bundleContext);
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+
+ bundle.start();
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/CREATED", properties));
+ bundle.stop();
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(0, signal.successCount);
+ assertEquals(0, signal.failures.size());
+ }
+
+ @Test
+ public void failureStateIsCleanedUpWhenBundleIsStopped() throws BundleException {
+ StubBundleContext bundleContext = new StubBundleContext();
+ StubBundle bundle = new StubBundle();
+ bundle.setBundleContext(bundleContext);
+ bundle.addHeader("Spring-Context", "foo");
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(bundleContext);
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+ properties.put("exception", new Exception());
+
+ bundle.start();
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/FAILURE", properties));
+ bundle.stop();
+
+ UnitTestSignal signal = new UnitTestSignal();
+
+ bundleStartTracker.trackStart(bundle, signal);
+
+ assertEquals(0, signal.successCount);
+ assertEquals(0, signal.failures.size());
+ }
+
+ private static final class UnitTestSignal implements Signal {
+
+ private final List<Throwable> failures = new ArrayList<Throwable>();
+
+ private int successCount = 0;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void signalFailure(Throwable cause) {
+ this.failures.add(cause);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void signalSuccessfulCompletion() {
+ successCount++;
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivatorTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivatorTests.java
new file mode 100644
index 00000000..23e73c22
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/CoreBundleActivatorTests.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.core.internal;
+
+import static org.easymock.EasyMock.createNiceMock;
+
+import java.io.File;
+
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.event.EventAdmin;
+
+
+import org.eclipse.virgo.kernel.StubConfigurationAdmin;
+import org.eclipse.virgo.kernel.core.Shutdown;
+import org.eclipse.virgo.kernel.core.internal.CoreBundleActivator;
+import org.eclipse.virgo.kernel.core.internal.StartupTracker;
+import org.eclipse.virgo.medic.dump.DumpGenerator;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+import org.eclipse.virgo.teststubs.osgi.service.event.StubEventAdmin;
+
+/**
+ * Test the logic of {@link CoreBundleActivator}
+ *
+ */
+public class CoreBundleActivatorTests {
+
+ @Test(expected = IllegalStateException.class)
+ public void noConfigService() throws Exception {
+ StubBundleContext bundleContext = new StubBundleContext();
+ bundleContext.addFilter(StartupTracker.APPLICATION_CONTEXT_FILTER, FrameworkUtil.createFilter(StartupTracker.APPLICATION_CONTEXT_FILTER));
+ CoreBundleActivator activator = new TestCoreBundleActivator();
+ activator.start(bundleContext);
+ }
+
+ @Test
+ public void startAndStop() throws Exception {
+ StubBundleContext bundleContext = new StubBundleContext();
+ DumpGenerator dumpGenerator = createNiceMock(DumpGenerator.class);
+ bundleContext.addFilter(StartupTracker.APPLICATION_CONTEXT_FILTER, FrameworkUtil.createFilter(StartupTracker.APPLICATION_CONTEXT_FILTER));
+ bundleContext.registerService(ConfigurationAdmin.class.getName(), new StubConfigurationAdmin(), null);
+ bundleContext.registerService(EventLogger.class.getName(), new MockEventLogger(), null);
+ bundleContext.registerService(EventAdmin.class.getName(), new StubEventAdmin(), null);
+ bundleContext.registerService(DumpGenerator.class.getName(), dumpGenerator, null);
+ bundleContext.addProperty("org.eclipse.virgo.kernel.domain", "test");
+ bundleContext.addProperty("org.eclipse.virgo.kernel.home", new File(".").getAbsolutePath());
+
+ CoreBundleActivator activator = new TestCoreBundleActivator();
+ activator.start(bundleContext);
+ activator.stop(bundleContext);
+ }
+
+ private static final class TestCoreBundleActivator extends CoreBundleActivator {
+ @Override
+ protected Shutdown createShutdown(BundleContext context, EventLogger eventLogger) {
+ return new Shutdown() {
+ public void immediateShutdown() {
+ }
+
+ public void shutdown() {
+ }
+ };
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/ShutdownManagerTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/ShutdownManagerTests.java
new file mode 100644
index 00000000..e07fee7c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/ShutdownManagerTests.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.launch.Framework;
+
+import org.eclipse.virgo.kernel.core.internal.ShutdownManager;
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+
+public class ShutdownManagerTests {
+
+ private final Framework framework = createMock(Framework.class);
+
+ private final MockEventLogger eventLogger = new MockEventLogger();
+
+ private final StubBundle bundle = new StubBundle();
+
+ private final StubBundleContext bundleContext = new StubBundleContext(bundle);
+
+ @Test
+ public void shutdown() throws BundleException, InterruptedException {
+
+ expect(this.framework.getBundleContext()).andReturn(this.bundleContext).anyTimes();
+ this.framework.stop();
+ expect(this.framework.waitForStop(30000)).andReturn(new FrameworkEvent(FrameworkEvent.STOPPED, this.bundle, null));
+
+ replay(this.framework);
+
+ ShutdownManager shutdownManager = new ShutdownManager(this.eventLogger, this.framework);
+ shutdownManager.shutdown();
+
+ verify(this.framework);
+ }
+
+ @Test
+ public void failedShutdownDrivesImmediateShutdown() throws Exception {
+ expect(this.framework.getBundleContext()).andReturn(this.bundleContext).anyTimes();
+ this.framework.stop();
+ expect(this.framework.waitForStop(30000)).andReturn(new FrameworkEvent(FrameworkEvent.WAIT_TIMEDOUT, this.bundle, null));
+
+ replay(this.framework);
+
+ UnitTestShutdownManager shutdownManager = new UnitTestShutdownManager(this.eventLogger, this.framework);
+ shutdownManager.shutdown();
+
+ verify(this.framework);
+
+ this.eventLogger.isLogged("KE0011I");
+ }
+
+ @Test
+ public void shutdownMessageLogged() {
+ expect(this.framework.getBundleContext()).andReturn(this.bundleContext).anyTimes();
+
+ replay(this.framework);
+ ShutdownManager shutdownManager = new ShutdownManager(this.eventLogger, this.framework);
+ verify(this.framework);
+
+ List<BundleListener> bundleListeners = this.bundleContext.getBundleListeners();
+
+ assertEquals(1, bundleListeners.size());
+ bundleListeners.get(0).bundleChanged(new BundleEvent(BundleEvent.STOPPING, this.bundle));
+
+ assertTrue(this.eventLogger.isLogged("KE0010I"));
+ }
+
+ private static final class UnitTestShutdownManager extends ShutdownManager {
+
+ public UnitTestShutdownManager(EventLogger eventLogger, Framework framework) {
+ super(eventLogger, framework);
+ }
+
+ @Override
+ public void exitVM() {
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/StartupTrackerTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/StartupTrackerTests.java
new file mode 100644
index 00000000..efb3f608
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/StartupTrackerTests.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * 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.core.internal;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.management.ManagementFactory;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.springframework.core.task.SyncTaskExecutor;
+
+
+import org.eclipse.virgo.kernel.config.internal.KernelConfiguration;
+import org.eclipse.virgo.kernel.core.Shutdown;
+import org.eclipse.virgo.kernel.core.internal.BundleStartTracker;
+import org.eclipse.virgo.kernel.core.internal.StartupTracker;
+import org.eclipse.virgo.medic.dump.DumpGenerator;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+import org.eclipse.virgo.teststubs.osgi.service.event.StubEventAdmin;
+import org.eclipse.virgo.teststubs.osgi.support.ObjectClassFilter;
+
+public class StartupTrackerTests {
+
+ private final StubBundleContext bundleContext = new StubBundleContext();
+
+ private final StubEventAdmin eventAdmin = new StubEventAdmin();
+
+ private final StubBundle bundle = new StubBundle("org.eclipse.virgo.kernel.startuptest", new Version(1,0,0));
+
+ private final Shutdown shutdown = createMock(Shutdown.class);
+
+ private final DumpGenerator dumpGenerator = createMock(DumpGenerator.class);
+
+ @Before
+ public void setup() {
+ this.bundleContext.addInstalledBundle(bundle);
+
+ this.bundleContext.addProperty("org.eclipse.virgo.kernel.home", "target");
+ this.bundleContext.addProperty("org.eclipse.virgo.kernel.domain", "the-domain");
+ this.bundleContext.addFilter(new ObjectClassFilter("org.springframework.context.ApplicationContext"));
+ this.bundleContext.registerService(EventAdmin.class.getName(), this.eventAdmin, null);
+
+ this.bundle.setBundleContext(bundleContext);
+ }
+
+ @Test
+ public void successfulStartup() throws Exception {
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(this.bundleContext);
+
+ StartupTracker tracker = new StartupTracker(this.bundleContext, new KernelConfiguration(this.bundleContext), 30, bundleStartTracker, this.shutdown, this.dumpGenerator);
+ tracker.start();
+
+ assertTrue(this.eventAdmin.awaitPostingOfEvent(new Event("org/eclipse/virgo/kernel/STARTING", null), 10000));
+
+ this.bundle.start();
+
+ assertTrue(this.eventAdmin.awaitPostingOfEvent(new Event("org/eclipse/virgo/kernel/STARTED", null), 10000));
+
+ tracker.stop();
+ }
+
+ @Test
+ @Ignore("[DMS-2424] timeout is now hard-coded at one hour and so cannot be tested conveniently")
+ public void startupTimeout() {
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(this.bundleContext);
+
+ this.bundle.addHeader("Spring-Context", "foo");
+
+ this.shutdown.immediateShutdown();
+ this.dumpGenerator.generateDump("startupTimedOut");
+
+ replay(this.shutdown, this.dumpGenerator);
+
+ StartupTracker tracker = new StartupTracker(this.bundleContext, new KernelConfiguration(this.bundleContext), 1, bundleStartTracker, this.shutdown, this.dumpGenerator);
+ tracker.start();
+
+ assertTrue(this.eventAdmin.awaitPostingOfEvent(new Event("org/eclipse/virgo/kernel/STARTING", null), 10000));
+ assertTrue(this.eventAdmin.awaitPostingOfEvent(new Event("org/eclipse/virgo/kernel/START_TIMED_OUT", null), 10000));
+
+ waitForABit(500);
+
+ tracker.stop();
+
+ verify(this.shutdown);
+ verify(this.dumpGenerator);
+ }
+
+ /**
+ * This method is used to allow actions taken after the events are posted to complete
+ * before making test verification checks. This is an artifact of the testing environment, and the waits
+ * should be no more than about 500 ms.
+ * @param milliSeconds time to wait
+ */
+ private void waitForABit(long milliSeconds) {
+ try {
+ Thread.sleep(milliSeconds);
+ } catch (InterruptedException _) {
+ }
+ }
+
+ @Test
+ public void startupFailed() throws InterruptedException {
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(this.bundleContext);
+
+ this.bundle.addHeader("Spring-Context", "foo");
+
+ this.shutdown.immediateShutdown();
+
+ Exception failure = new Exception();
+ this.dumpGenerator.generateDump("startupFailed", failure);
+
+ replay(this.shutdown, this.dumpGenerator);
+
+ StartupTracker tracker = new StartupTracker(this.bundleContext, new KernelConfiguration(this.bundleContext), 1, bundleStartTracker, this.shutdown, this.dumpGenerator);
+ tracker.start();
+
+ assertTrue(this.eventAdmin.awaitPostingOfEvent(new Event("org/eclipse/virgo/kernel/STARTING", null), 10000));
+
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("bundle", bundle);
+ properties.put("exception", failure);
+
+ bundleStartTracker.handleEvent(new Event("org/osgi/service/blueprint/container/FAILURE", properties));
+
+ assertTrue(this.eventAdmin.awaitPostingOfEvent(new Event("org/eclipse/virgo/kernel/START_FAILED", null), 10000));
+
+ waitForABit(500);
+
+ tracker.stop();
+
+ verify(this.shutdown, this.dumpGenerator);
+ }
+
+
+ @Test
+ public void statusMBeanRegistration() throws Exception {
+ assertMBeanNotRegistered();
+
+ BundleStartTracker bundleStartTracker = new BundleStartTracker(new SyncTaskExecutor());
+ bundleStartTracker.initialize(this.bundleContext);
+
+ StartupTracker tracker = new StartupTracker(this.bundleContext, new KernelConfiguration(this.bundleContext), 1, bundleStartTracker, this.shutdown, this.dumpGenerator);
+ tracker.start();
+
+ assertMBeanRegistered();
+
+ tracker.stop();
+
+ assertMBeanNotRegistered();
+ }
+
+ private void assertMBeanRegistered() throws Exception {
+ assertTrue(isMBeanRegistered());
+ }
+
+ private void assertMBeanNotRegistered() throws Exception {
+ assertFalse(isMBeanRegistered());
+ }
+
+ private boolean isMBeanRegistered() throws Exception {
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ return mBeanServer.isRegistered(new ObjectName("the-domain", "type", "KernelStatus"));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitorTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitorTests.java
new file mode 100644
index 00000000..168dc5a6
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/ApplicationContextDependencyMonitorTests.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * 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.core.internal.blueprint;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.junit.Test;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+
+import org.eclipse.virgo.kernel.core.internal.blueprint.ApplicationContextDependencyMonitor;
+import org.eclipse.virgo.medic.test.eventlog.LoggedEvent;
+import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+
+/**
+ */
+public class ApplicationContextDependencyMonitorTests {
+
+ private final MockEventLogger eventLogger = new MockEventLogger();
+
+ private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+
+ private final ApplicationContextDependencyMonitor dependencyMonitor = new ApplicationContextDependencyMonitor(executor, eventLogger);
+
+ private final StubBundle bundle = new StubBundle("the.bundle", new Version(1, 2, 3));
+
+ @Test
+ public void loggingOfWaitingEventForMandatoryService() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(6000);
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(1, loggedEvents.size());
+
+ LoggedEvent loggedEvent = loggedEvents.get(0);
+
+ assertEquals("KE0100W", loggedEvent.getCode());
+ Object[] inserts = loggedEvent.getInserts();
+ assertEquals(4, inserts.length);
+
+ assertEquals("theBean", inserts[0]);
+ assertEquals(this.bundle.getSymbolicName(), inserts[1]);
+ assertEquals(this.bundle.getVersion(), inserts[2]);
+ assertEquals("filter", inserts[3]);
+ }
+
+ @Test
+ public void loggingOfWaitingEventForOptionalService() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", false));
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(6000);
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(1, loggedEvents.size());
+
+ LoggedEvent loggedEvent = loggedEvents.get(0);
+
+ assertEquals("KE0100W", loggedEvent.getCode());
+ Object[] inserts = loggedEvent.getInserts();
+ assertEquals(4, inserts.length);
+
+ assertEquals("theBean", inserts[0]);
+ assertEquals(this.bundle.getSymbolicName(), inserts[1]);
+ assertEquals(this.bundle.getVersion(), inserts[2]);
+ assertEquals("filter", inserts[3]);
+ }
+
+ @Test
+ public void loggingOfDependencySatisfied() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(6000);
+
+ event = new Event("org/osgi/service/blueprint/container/GRACE_PERIOD", createProperties());
+ this.dependencyMonitor.handleEvent(event);
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(2, loggedEvents.size());
+
+ LoggedEvent loggedEvent = loggedEvents.get(1);
+
+ assertEquals("KE0101I", loggedEvent.getCode());
+ Object[] inserts = loggedEvent.getInserts();
+ assertEquals(4, inserts.length);
+
+ assertEquals("theBean", inserts[0]);
+ assertEquals(this.bundle.getSymbolicName(), inserts[1]);
+ assertEquals(this.bundle.getVersion(), inserts[2]);
+ assertEquals("filter", inserts[3]);
+ }
+
+ @Test
+ public void loggingOfMandatoryDependencyTimedOut() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(6000);
+
+ event = new Event("org/osgi/service/blueprint/container/FAILURE", createProperties("filter", "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(2, loggedEvents.size());
+
+ LoggedEvent loggedEvent = loggedEvents.get(1);
+
+ assertEquals("KE0102E", loggedEvent.getCode());
+ Object[] inserts = loggedEvent.getInserts();
+ assertEquals(4, inserts.length);
+
+ assertEquals("theBean", inserts[0]);
+ assertEquals(this.bundle.getSymbolicName(), inserts[1]);
+ assertEquals(this.bundle.getVersion(), inserts[2]);
+ assertEquals("filter", inserts[3]);
+ }
+
+ @Test
+ public void loggingOfOptionalDependencyTimedOut() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", false));
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(6000);
+
+ event = new Event("org/osgi/service/blueprint/container/FAILURE", createProperties("filter", "theBean", false));
+ this.dependencyMonitor.handleEvent(event);
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(2, loggedEvents.size());
+
+ LoggedEvent loggedEvent = loggedEvents.get(1);
+
+ assertEquals("KE0102E", loggedEvent.getCode());
+ Object[] inserts = loggedEvent.getInserts();
+ assertEquals(4, inserts.length);
+
+ assertEquals("theBean", inserts[0]);
+ assertEquals(this.bundle.getSymbolicName(), inserts[1]);
+ assertEquals(this.bundle.getVersion(), inserts[2]);
+ assertEquals("filter", inserts[3]);
+ }
+
+ @Test
+ public void containerCreationFailureRemovesTickers() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ event = new Event("org/osgi/service/blueprint/container/FAILURE", createProperties());
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(3000);
+
+ assertFalse(this.eventLogger.getCalled());
+ }
+
+ @Test
+ public void containerCreationDrivesOutstandingTickers() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(6000);
+
+ event = new Event("org/osgi/service/blueprint/container/CREATED", createProperties());
+ this.dependencyMonitor.handleEvent(event);
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(2, loggedEvents.size());
+
+ LoggedEvent loggedEvent = loggedEvents.get(1);
+
+ assertEquals("KE0101I", loggedEvent.getCode());
+ Object[] inserts = loggedEvent.getInserts();
+ assertEquals(4, inserts.length);
+
+ assertEquals("theBean", inserts[0]);
+ assertEquals(this.bundle.getSymbolicName(), inserts[1]);
+ assertEquals(this.bundle.getVersion(), inserts[2]);
+ assertEquals("filter", inserts[3]);
+ }
+
+ @Test
+ public void dependencyThatIsSatisfiedQuicklyLogsNothing() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("filter", "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ event = new Event("org/osgi/service/blueprint/container/GRACE_PERIOD", createProperties());
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(3000);
+
+ List<LoggedEvent> loggedEvents = this.eventLogger.getLoggedEvents();
+ assertEquals(0, loggedEvents.size());
+ }
+
+ @Test
+ public void slowServicesAreGivenLongerToBecomeAvailable() throws InterruptedException {
+ Event event = new Event("org/osgi/service/blueprint/container/WAITING", createProperties("(org.eclipse.virgo.server.slowservice=true)",
+ "theBean", true));
+ this.dependencyMonitor.handleEvent(event);
+
+ Thread.sleep(3000);
+
+ assertFalse(this.eventLogger.getCalled());
+ }
+
+ @Test
+ public void containerCreatedNotWaiting() {
+ Event event = new Event("org/osgi/service/blueprint/container/CREATED", createProperties());
+ this.dependencyMonitor.handleEvent(event);
+ }
+
+ @Test
+ public void changeInUnsatisfiedDependenciesNotWaiting() {
+ Event event = new Event("org/osgi/service/blueprint/container/GRACE_PERIOD", createProperties());
+ this.dependencyMonitor.handleEvent(event);
+ }
+
+ @Test
+ public void serviceDependenciesTimedOutNotWaiting() {
+ Event event = new Event("org/osgi/service/blueprint/container/FAILURE", createProperties("filter", "theBean", false));
+ this.dependencyMonitor.handleEvent(event);
+ }
+
+ @Test
+ public void containerCreationFailedNotWaiting() {
+ Event event = new Event("org/osgi/service/blueprint/container/FAILURE", createProperties());
+ this.dependencyMonitor.handleEvent(event);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Dictionary createProperties(String filter, String beanName, boolean mandatory) {
+ Dictionary properties = createProperties();
+
+ properties.put("dependencies", new String[] { filter });
+ properties.put("bean.name", new String[] { beanName });
+ properties.put("mandatory", new boolean[] { mandatory });
+
+ return properties;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Dictionary createProperties() {
+ Dictionary properties = new Hashtable();
+ properties.put(EventConstants.BUNDLE, this.bundle);
+ return properties;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/TickerTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/TickerTests.java
new file mode 100644
index 00000000..3ea4606b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/core/internal/blueprint/TickerTests.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.core.internal.blueprint;
+
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+
+import org.eclipse.virgo.kernel.core.internal.blueprint.StandardTicker;
+import org.eclipse.virgo.kernel.core.internal.blueprint.Ticker;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/**
+ */
+public class TickerTests {
+
+ private volatile int ticks;
+
+ @Test public void testTicker() throws InterruptedException {
+ this.ticks = 0;
+ Ticker ticker = StandardTicker.createExponentialTicker(20, 100, 60 * 1000, new Callable<Void>() {
+
+ public Void call() throws Exception {
+ TickerTests.this.ticks++;
+ return null;
+ }}, new ScheduledThreadPoolExecutor(1));
+
+ Thread.sleep(2000);
+ ticker.cancel();
+
+ Assert.assertEquals(6, ticks);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/AssertTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/AssertTests.java
new file mode 100644
index 00000000..431d75cd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/AssertTests.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * 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.serviceability;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.virgo.kernel.serviceability.Assert;
+import org.eclipse.virgo.kernel.serviceability.Assert.FatalAssertionException;
+import org.junit.Test;
+
+
+/**
+ */
+public class AssertTests {
+
+ @Test
+ public void testHasLength() {
+ try {
+ Assert.hasLength(null, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.hasLength("", "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Assert.hasLength("x", "blah");
+ }
+
+ @Test
+ public void testIsAssignable() {
+ try {
+ Assert.isAssignable(String.class, Object.class, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.isAssignable(null, Object.class, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.isAssignable(Object.class, null, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Assert.isAssignable(Object.class, Object.class, "blah");
+ Assert.isAssignable(Object.class, String.class, "blah");
+ }
+
+ @Test
+ public void testIsInstanceOf() {
+ try {
+ Assert.isInstanceOf(Integer.class, "", "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.isInstanceOf(null, "", "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.isInstanceOf(Integer.class, null, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Assert.isInstanceOf(String.class, "", "blah");
+ }
+
+ @Test
+ public void testIsNull() {
+ try {
+ Assert.isNull("", "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Assert.isNull(null, "blah");
+ }
+
+ @Test
+ public void testIsTrue() {
+ try {
+ Assert.isTrue(false, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Assert.isTrue(true, "blah");
+ }
+
+ @Test
+ public void testIsFalse() {
+ try {
+ Assert.isFalse(true, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Assert.isFalse(false, "blah");
+ }
+
+ @Test
+ public void testNotEmptyCollection() {
+ try {
+ Assert.notEmpty(new HashSet<String>(), "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.notEmpty((Collection<String>)null, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Set<String> a = new HashSet<String>();
+ a.add("x");
+ Assert.notEmpty(a, "blah");
+ }
+
+ @Test
+ public void testNotEmptyMap() {
+ try {
+ Assert.notEmpty(new HashMap<String, String>(), "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.notEmpty((Map<String, String>)null, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Map<String, String> a = new HashMap<String, String>();
+ a.put("k", "v");
+ Assert.notEmpty(a, "blah");
+ }
+
+ @Test
+ public void testNotEmptyArray() {
+ try {
+ Object[] a = {};
+ Assert.notEmpty(a, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ try {
+ Assert.notEmpty((Object[])null, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Object[] a = {"x"};
+ Assert.notEmpty(a, "blah");
+ }
+
+ @Test
+ public void testNotNull() {
+ try {
+ Assert.notNull(null, "blah");
+ org.junit.Assert.assertTrue(false);
+ } catch (FatalAssertionException e) {
+ }
+ Assert.notNull("x", "blah");
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionStateTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionStateTests.java
new file mode 100644
index 00000000..d67bbeff
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/dump/FFDCExceptionStateTests.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * 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.serviceability.dump;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.eclipse.virgo.kernel.serviceability.dump.FFDCExceptionState;
+import org.junit.Test;
+
+
+public class FFDCExceptionStateTests {
+
+ @Test
+ public void seen() {
+ Throwable throwable = new Throwable();
+ assertFalse(FFDCExceptionState.seen(throwable));
+ FFDCExceptionState.record(throwable);
+ assertTrue(FFDCExceptionState.seen(throwable));
+ }
+
+ @Test
+ public void multithreadedSeen() {
+ final Throwable throwable = new Throwable();
+ FFDCExceptionState.record(throwable);
+ assertTrue(FFDCExceptionState.seen(throwable));
+ SeenChecker checker = new SeenChecker(throwable);
+ checker.start();
+ assertFalse(checker.seen());
+ }
+
+ @Test
+ public void seenAsNestedCause() {
+ Throwable nested = new Throwable();
+ FFDCExceptionState.record(nested);
+ Throwable root = new Throwable(nested);
+ assertTrue(FFDCExceptionState.seen(root));
+ }
+
+ private class SeenChecker extends Thread {
+
+ private final Throwable throwable;
+ private volatile boolean seen;
+ private final CountDownLatch latch;
+
+ public SeenChecker(Throwable throwable) {
+ this.throwable = throwable;
+ this.latch = new CountDownLatch(1);
+ }
+
+ public boolean seen() {
+ boolean awaiting = true;
+ while (awaiting) {
+ try {
+ this.latch.await();
+ awaiting = false;
+ } catch (InterruptedException ie) {
+
+ }
+ }
+ return this.seen;
+ }
+
+ public void run() {
+ seen = FFDCExceptionState.seen(throwable);
+ latch.countDown();
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcerTests.java b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcerTests.java
new file mode 100644
index 00000000..413359b4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/org/eclipse/virgo/kernel/serviceability/enforcement/NonNullAssertionEnforcerTests.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.serviceability.enforcement;
+
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import test.AssertingService;
+
+import org.eclipse.virgo.kernel.serviceability.Assert;
+import org.eclipse.virgo.kernel.serviceability.dump.DumpCoordinator;
+import org.eclipse.virgo.medic.dump.DumpGenerator;
+
+public class NonNullAssertionEnforcerTests {
+
+ @Before
+ public void injectDumpGenerator() {
+ DumpCoordinator.aspectOf().setDumpGenerator(new StubDumpGenerator());
+ }
+
+ @Test(expected = Assert.FatalAssertionException.class)
+ public void firstMethodArg() {
+ AssertingService service = new AssertingService();
+ service.test(null);
+ }
+
+ @Test(expected = Assert.FatalAssertionException.class)
+ public void secondMethodArg() {
+ AssertingService service = new AssertingService();
+ service.test("foo", null);
+ }
+
+ @Test(expected = Assert.FatalAssertionException.class)
+ public void thirdMethodArg() {
+ AssertingService service = new AssertingService();
+ service.test("foo", 1, null);
+ }
+
+ @Test(expected = Assert.FatalAssertionException.class)
+ public void firstConstructorArg() {
+ new AssertingService(null);
+ }
+
+ @Test(expected = Assert.FatalAssertionException.class)
+ public void secondConstructorArg() {
+ new AssertingService("foo", null);
+ }
+
+ @Test(expected = Assert.FatalAssertionException.class)
+ public void thirdConstructorArg() {
+ new AssertingService("foo", 1, null);
+ }
+
+ private static class StubDumpGenerator implements DumpGenerator {
+
+ public void generateDump(String cause, Throwable... throwables) {
+ }
+
+ public void generateDump(String cause, Map<String, Object> context, Throwable... throwables) {
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/java/test/AssertingService.java b/org.eclipse.virgo.kernel.core/src/test/java/test/AssertingService.java
new file mode 100644
index 00000000..006c96b2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/java/test/AssertingService.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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 test;
+
+import org.eclipse.virgo.kernel.serviceability.NonNull;
+
+
+/**
+ */
+@SuppressWarnings("unused")
+public class AssertingService {
+
+ public AssertingService() {
+
+ }
+
+ public AssertingService( @NonNull String a) {
+
+ }
+
+ public AssertingService(String a, @NonNull Integer b) {
+
+ }
+
+ public AssertingService(String a, Integer b, @NonNull Double c) {
+
+ }
+
+ public void test(@NonNull String a) {
+ }
+
+ public void test(@NonNull String a, @NonNull Integer b) {
+
+ }
+
+ public void test(String a, Integer b, @NonNull Double d) {
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_badprops/noprops.properties b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_badprops/noprops.properties
new file mode 100644
index 00000000..b419c60e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_badprops/noprops.properties
@@ -0,0 +1,2 @@
+
+!@£$%^&*()_
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise.config b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise.config
new file mode 100644
index 00000000..f13418ca
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise.config
@@ -0,0 +1,11 @@
+{
+ "types": {
+ "int" : 123,
+ "string": "foo",
+ "boolean": true,
+ "path1": "foo/bar",
+ "path2": "/foo/bar",
+ "path3": "../../foo/bar",
+ "path4": "/foo/../bar"
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise2.config b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise2.config
new file mode 100644
index 00000000..f13418ca
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_noprops/noise2.config
@@ -0,0 +1,11 @@
+{
+ "types": {
+ "int" : 123,
+ "string": "foo",
+ "boolean": true,
+ "path1": "foo/bar",
+ "path2": "/foo/bar",
+ "path3": "../../foo/bar",
+ "path4": "/foo/../bar"
+ }
+}
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props1/dup.properties b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props1/dup.properties
new file mode 100644
index 00000000..30aee8b2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props1/dup.properties
@@ -0,0 +1,3 @@
+# Properties file for Config Admin service configuration properties.
+test=This is a test string
+dup_prop=Duplicate property one
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props2/dup.properties b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props2/dup.properties
new file mode 100644
index 00000000..f700caf3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ConfigBundleTests/config_tests_props2/dup.properties
@@ -0,0 +1,6 @@
+# Properties file for Config Admin service configuration properties.
+test=This is a test string as well
+dup_prop=Duplicate property two
+hidden=Hidden property
+boolean=false
+integer=1024
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/one.properties b/org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/one.properties
new file mode 100644
index 00000000..74d0a43f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/one.properties
@@ -0,0 +1 @@
+foo=bar
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/two.properties b/org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/two.properties
new file mode 100644
index 00000000..eacf225c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/UserConfigurationPropertiesSourceTests/two.properties
@@ -0,0 +1 @@
+bar=baz
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ovf/environment.xml b/org.eclipse.virgo.kernel.core/src/test/resources/ovf/environment.xml
new file mode 100644
index 00000000..9c16f830
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ovf/environment.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Environment xmlns="http://schemas.dmtf.org/ovf/environment/1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1"
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/environment/1 http://schemas.dmtf.org/ovf/environment/1/dsp8027.xsd"
+ ovfenv:id="DB1">
+
+ <!-- This example reference a local schema file, to validate against online schema use:
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8027_1.0.0.xsd"
+ -->
+
+ <!-- Information about hypervisor platform -->
+ <PlatformSection>
+ <Kind>ESX Server</Kind>
+ <Version>3.0.1</Version>
+ <Vendor>VMware, Inc.</Vendor>
+ <Locale>en_US</Locale>
+ </PlatformSection>
+
+ <!--- Properties defined for this virtual machine -->
+ <PropertySection>
+ <Property ovfenv:key="com.myapp.foo" ovfenv:value="bar"/>
+ <Property ovfenv:key="com.myapp.bar" ovfenv:value="baz"/>
+ </PropertySection>
+
+</Environment>
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ovf/invalid.xml b/org.eclipse.virgo.kernel.core/src/test/resources/ovf/invalid.xml
new file mode 100644
index 00000000..ee406ee4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ovf/invalid.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Environment xmlns="http://schemas.dmtf.org/ovf/environment/1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1"
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/environment/1 http://schemas.dmtf.org/ovf/environment/1/dsp8027.xsd"
+ ovfenv:id="DB1">
+
+ <!-- This example reference a local schema file, to validate against online schema use:
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8027_1.0.0.xsd"
+ -->
+
+ <!-- Information about hypervisor platform -->
+ <PlatformSection>
+ <Kind>ESX Server</Kind>
+ <Version>3.0.1</Version>
+ <Vendor>VMware, Inc.</Vendor>
+ <Locale>en_US</Locale>
+ </PlatformSection>
+
+ <!--- Properties defined for this virtual machine -->
+ <PropertySection>
+ <Property ovfenv:key="cm:invalid" ovfenv:value="bar"/>
+ </PropertySection>
+
+</Environment>
diff --git a/org.eclipse.virgo.kernel.core/src/test/resources/ovf/valid.xml b/org.eclipse.virgo.kernel.core/src/test/resources/ovf/valid.xml
new file mode 100644
index 00000000..aff0fc60
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/src/test/resources/ovf/valid.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Environment xmlns="http://schemas.dmtf.org/ovf/environment/1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1"
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/environment/1 http://schemas.dmtf.org/ovf/environment/1/dsp8027.xsd"
+ ovfenv:id="DB1">
+
+ <!-- This example reference a local schema file, to validate against online schema use:
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8027_1.0.0.xsd"
+ -->
+
+ <!-- Information about hypervisor platform -->
+ <PlatformSection>
+ <Kind>ESX Server</Kind>
+ <Version>3.0.1</Version>
+ <Vendor>VMware, Inc.</Vendor>
+ <Locale>en_US</Locale>
+ </PlatformSection>
+
+ <!--- Properties defined for this virtual machine -->
+ <PropertySection>
+ <Property ovfenv:key="cm:one:foo" ovfenv:value="bar"/>
+ <Property ovfenv:key="cm:one:bar" ovfenv:value="baz"/>
+ <Property ovfenv:key="cm:two:baz" ovfenv:value="quux"/>
+ <Property ovfenv:key="some.random.property" ovfenv:value="value"/>
+ </PropertySection>
+
+</Environment>
diff --git a/org.eclipse.virgo.kernel.core/template.mf b/org.eclipse.virgo.kernel.core/template.mf
new file mode 100644
index 00000000..28f41762
--- /dev/null
+++ b/org.eclipse.virgo.kernel.core/template.mf
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Virgo Kernel Core
+Bundle-Activator: org.eclipse.virgo.kernel.core.internal.CoreBundleActivator
+Bundle-SymbolicName: org.eclipse.virgo.kernel.core
+Bundle-Version: 2.1.0
+Import-Template:
+ org.eclipse.virgo.util.*;version="${org.eclipse.virgo.util:[=.=.=, =.+1)}",
+ org.eclipse.virgo.medic.*;version="${org.eclipse.virgo.medic:[=.=.=, =.+1)}",
+ org.slf4j.*;version="${org.slf4j:[=.=.=, +1)}",
+ org.aspectj.*;version="${org.aspectj:[=.=.=.=, +1)}",
+ javax.management.*;version="0",
+ javax.xml.parsers;version="0",
+ org.osgi.*;version="0",
+ org.springframework.*;version="${org.springframework:[2.5.6, =.+1)}",
+ org.springframework.osgi.*;version="${org.springframework.osgi:[=.=.=, +1)}",
+ org.w3c.dom;version="0",
+ org.xml.sax;version="0"
+Excluded-Exports:
+ *.internal.*
+Excluded-Imports: org.eclipse.virgo.osgi.extensions.*

Back to the top