Move ServiceMix Kernel trunk into Felix
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@768912 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/testing/itests/pom.xml b/karaf/testing/itests/pom.xml
new file mode 100644
index 0000000..8442902
--- /dev/null
+++ b/karaf/testing/itests/pom.xml
@@ -0,0 +1,77 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.servicemix.kernel.testing</groupId>
+ <artifactId>testing</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.servicemix.kernel.testing</groupId>
+ <artifactId>org.apache.servicemix.kernel.testing.itests</artifactId>
+ <packaging>jar</packaging>
+ <version>1.2.0-SNAPSHOT</version>
+ <name>Apache ServiceMix Kernel :: Testing - ITests</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.servicemix.kernel.testing</groupId>
+ <artifactId>org.apache.servicemix.kernel.testing.support</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.specs</groupId>
+ <artifactId>org.apache.servicemix.specs.jaxp-api-1.4</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.woodstox</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.jaxp-ri</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- generate dependencies versions -->
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-depends-file</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/karaf/testing/itests/src/test/java/org/apache/servicemix/kernel/testing/itests/SimpleTest.java b/karaf/testing/itests/src/test/java/org/apache/servicemix/kernel/testing/itests/SimpleTest.java
new file mode 100644
index 0000000..dec38ae
--- /dev/null
+++ b/karaf/testing/itests/src/test/java/org/apache/servicemix/kernel/testing/itests/SimpleTest.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.itests;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.servicemix.kernel.testing.support.AbstractIntegrationTest;
+import org.osgi.framework.Bundle;
+
+public class SimpleTest extends AbstractIntegrationTest {
+
+ static {
+ System.setProperty("jaxp.debug", "true");
+ System.setProperty("org.apache.servicemix.specs.debug", "true");
+ }
+
+ /**
+ * The manifest to use for the "virtual bundle" created
+ * out of the test classes and resources in this project
+ *
+ * This is actually the boilerplate manifest with one additional
+ * import-package added. We should provide a simpler customization
+ * point for such use cases that doesn't require duplication
+ * of the entire manifest...
+ */
+ protected String getManifestLocation() {
+ return "classpath:org/apache/servicemix/MANIFEST.MF";
+ }
+
+ /**
+ * The location of the packaged OSGi bundles to be installed
+ * for this test. Values are Spring resource paths. The bundles
+ * we want to use are part of the same multi-project maven
+ * build as this project is. Hence we use the localMavenArtifact
+ * helper method to find the bundles produced by the package
+ * phase of the maven build (these tests will run after the
+ * packaging phase, in the integration-test phase).
+ *
+ * JUnit, commons-logging, spring-core and the spring OSGi
+ * test bundle are automatically included so do not need
+ * to be specified here.
+ */
+ protected String[] getTestBundlesNames() {
+ return new String[0];
+ }
+
+ /**
+ * Do not include the jaxp-ri bundle by default, as we want to test it
+ * @return
+ */
+ @Override
+ protected String[] getTestFrameworkBundlesNames() {
+ return new String[] {
+ getBundle("org.apache.geronimo.specs", "geronimo-servlet_2.5_spec"),
+ getBundle("org.apache.servicemix.specs", "org.apache.servicemix.specs.jaxp-api-1.4"),
+ getBundle("org.apache.felix", "org.osgi.compendium"),
+ getBundle("org.apache.felix", "org.apache.felix.configadmin"),
+ getBundle("org.ops4j.pax.logging", "pax-logging-api"),
+ getBundle("org.ops4j.pax.logging", "pax-logging-service"),
+ getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.aopalliance"),
+ getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.asm"),
+ getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.junit"),
+ getBundle("org.springframework", "spring-beans"),
+ getBundle("org.springframework", "spring-core"),
+ getBundle("org.springframework", "spring-context"),
+ getBundle("org.springframework", "spring-aop"),
+ getBundle("org.springframework", "spring-test"),
+ getBundle("org.springframework.osgi", "spring-osgi-core"),
+ getBundle("org.springframework.osgi", "spring-osgi-io"),
+ getBundle("org.springframework.osgi", "spring-osgi-extender"),
+ getBundle("org.springframework.osgi", "spring-osgi-test"),
+ getBundle("org.springframework.osgi", "spring-osgi-annotation"),
+ getBundle("org.apache.servicemix.kernel.testing", "org.apache.servicemix.kernel.testing.support"),
+ };
+ }
+
+ public void testDocumentBuilderFactory() throws Exception {
+ try {
+ DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ fail("Implementation should not have been found");
+ } catch (Throwable t) {
+ }
+ Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+ try {
+ assertNotNull(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
+ } finally {
+ b.uninstall();
+ }
+ }
+
+ public void testTransformerFactory() throws Exception {
+ try {
+ TransformerFactory.newInstance().newTransformer();
+ fail("Implementation should not have been found");
+ } catch (Throwable t) {
+ }
+ Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+ try {
+ assertNotNull(TransformerFactory.newInstance().newTransformer());
+ } finally {
+ b.uninstall();
+ }
+ }
+
+ public void testSchemaFactory() throws Exception {
+ try {
+ SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema").newSchema();
+ fail("Implementation should not have been found");
+ } catch (Throwable t) {
+ }
+ Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+ try {
+ assertNotNull(SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema").newSchema());
+ } finally {
+ b.uninstall();
+ }
+ }
+
+ public void testStax() throws Exception {
+ try {
+ XMLInputFactory.newInstance();
+ fail("Implementation should not have been found");
+ } catch (Throwable t) {
+ }
+ Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+ try {
+ assertNotNull(XMLInputFactory.newInstance());
+ } finally {
+ b.uninstall();
+ }
+ }
+
+}
diff --git a/karaf/testing/itests/src/test/resources/log4j.properties b/karaf/testing/itests/src/test/resources/log4j.properties
new file mode 100644
index 0000000..7944dfb
--- /dev/null
+++ b/karaf/testing/itests/src/test/resources/log4j.properties
@@ -0,0 +1,43 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+#
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=DEBUG, stdout
+
+log4j.logger.org.springframework=INFO
+log4j.logger.org.apache.activemq=INFO
+log4j.logger.org.apache.activemq.spring=WARN
+
+
+#log4j.logger.org.apache.servicemix=DEBUG
+
+# CONSOLE appender
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/servicemix-test.log
+log4j.appender.out.append=true
diff --git a/karaf/testing/itests/src/test/resources/org/apache/servicemix/MANIFEST.MF b/karaf/testing/itests/src/test/resources/org/apache/servicemix/MANIFEST.MF
new file mode 100644
index 0000000..f26d98a
--- /dev/null
+++ b/karaf/testing/itests/src/test/resources/org/apache/servicemix/MANIFEST.MF
@@ -0,0 +1,32 @@
+Manifest-Version: 1.0
+License-00: .
+License-01: Licensed to the Apache Software Foundation (ASF) under one or more
+License-02: contributor license agreements. See the NOTICE file distributed with
+License-03: this work for additional information regarding copyright ownership.
+License-04: The ASF licenses this file to You under the Apache License, Version 2.0
+License-05: (the "License"); you may not use this file except in compliance with
+License-06: the License. You may obtain a copy of the License at
+License-07: .
+License-08: http://www.apache.org/licenses/LICENSE-2.0
+License-09: .
+License-10: Unless required by applicable law or agreed to in writing, software
+License-11: distributed under the License is distributed on an "AS IS" BASIS,
+License-12: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+License-13: See the License for the specific language governing permissions and
+License-14: limitations under the License.
+License-15: .
+Bundle-Name: org.apache.servicemix.testing.itests
+Bundle-SymbolicName: org.apache.servicemix.testing.itests
+Bundle-Vendor: Spring Framework
+Bundle-Activator: org.springframework.osgi.test.JUnitTestActivator
+Import-Package: junit.framework,
+ org.osgi.framework;specification-version="1.3.0",
+ org.apache.commons.logging,
+ org.springframework.core.io,
+ org.springframework.osgi.test,
+ org.apache.servicemix.kernel.testing.support,
+ org.springframework.osgi.util,
+ javax.xml.stream,
+ javax.xml.transform,
+ javax.xml.validation,
+ javax.xml.parsers
diff --git a/karaf/testing/pom.xml b/karaf/testing/pom.xml
new file mode 100644
index 0000000..9a62891
--- /dev/null
+++ b/karaf/testing/pom.xml
@@ -0,0 +1,41 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.servicemix.kernel</groupId>
+ <artifactId>kernel</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.servicemix.kernel.testing</groupId>
+ <artifactId>testing</artifactId>
+ <packaging>pom</packaging>
+ <version>1.2.0-SNAPSHOT</version>
+ <name>Apache ServiceMix Kernel :: Testing</name>
+
+ <modules>
+ <module>support</module>
+ <module>itests</module>
+ </modules>
+
+</project>
diff --git a/karaf/testing/support/pom.xml b/karaf/testing/support/pom.xml
new file mode 100644
index 0000000..7eb620a
--- /dev/null
+++ b/karaf/testing/support/pom.xml
@@ -0,0 +1,149 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.servicemix.kernel.testing</groupId>
+ <artifactId>testing</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.servicemix.kernel.testing</groupId>
+ <artifactId>org.apache.servicemix.kernel.testing.support</artifactId>
+ <packaging>bundle</packaging>
+ <version>1.2.0-SNAPSHOT</version>
+ <name>Apache ServiceMix Kernel :: Testing - Support</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.servicemix.kernel</groupId>
+ <artifactId>org.apache.servicemix.kernel.main</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.logging</groupId>
+ <artifactId>pax-logging-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.logging</groupId>
+ <artifactId>pax-logging-service</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-test</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-extender</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-annotation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-servlet_2.5_spec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.specs</groupId>
+ <artifactId>org.apache.servicemix.specs.jaxp-api-1.4</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.asm</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.woodstox</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.jaxp-ri</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-mvn</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resources</id>
+ <!-- here the phase you need -->
+ <phase>compile</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/target/classes/org/apache/servicemix/kernel/testing/support/</outputDirectory>
+ <resources>
+ <resource>
+ <directory>../../${config.location}</directory>
+ <includes>
+ <include>config.properties</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+ <Import-Package>
+ org.apache.felix*;resolution:=optional,
+ org.apache.servicemix.kernel.main;resolution:=optional,
+ org.apache.servicemix.kernel.main.spi;resolution:=optional;version="1.0.0",
+ *
+ </Import-Package>
+ <Export-Package>${pom.artifactId}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTest.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTest.java
new file mode 100644
index 0000000..14cc73a
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTest.java
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.log4j.PropertyConfigurator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.osgi.test.AbstractConfigurableBundleCreatorTests;
+import org.springframework.osgi.test.provisioning.ArtifactLocator;
+import org.springframework.osgi.util.OsgiFilterUtils;
+import org.springframework.osgi.util.OsgiListenerUtils;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+
+public class AbstractIntegrationTest extends AbstractConfigurableBundleCreatorTests {
+
+ static {
+ try {
+ File f = new File("target/smx4");
+ f.mkdirs();
+ System.setProperty("servicemix.name", "root");
+ System.setProperty("servicemix.home", f.getAbsolutePath());
+ System.setProperty("servicemix.base", f.getAbsolutePath());
+ System.setProperty("org.apache.servicemix.filemonitor.configDir", new File(f, "etc").getAbsolutePath());
+ System.setProperty("org.apache.servicemix.filemonitor.monitorDir", new File(f, "deploy").getAbsolutePath());
+ System.setProperty("org.apache.servicemix.filemonitor.generatedJarDir", new File(f, "data/generate-bundles").getAbsolutePath());
+ System.setProperty("bundles.configuration.location", new File("src/test/conf").getAbsolutePath());
+ System.setProperty("org.osgi.vendor.framework", "org.apache.servicemix.kernel.testing.support");
+ PropertyConfigurator.configure("target/test-classes/log4j.properties");
+ } catch (Throwable t) {}
+ }
+
+ private Properties dependencies;
+ private FeatureInstaller featureInstaller;
+
+ @Override
+ protected String getPlatformName() {
+ String systemProperty = System.getProperty(OSGI_FRAMEWORK_SELECTOR);
+ if (logger.isTraceEnabled())
+ logger.trace("system property [" + OSGI_FRAMEWORK_SELECTOR + "] has value=" + systemProperty);
+
+ return (systemProperty == null ? SmxKernelPlatform.class.getName() : systemProperty);
+ }
+
+ protected String getBundle(String groupId, String artifactId) {
+ return groupId + "," + artifactId + "," + getBundleVersion(groupId, artifactId);
+ }
+
+ protected String getBundleVersion(String groupId, String artifactId) {
+ if (dependencies == null) {
+ try {
+ File f = new File(System.getProperty("basedir"), "target/classes/META-INF/maven/dependencies.properties");
+ Properties prop = new Properties();
+ prop.load(new FileInputStream(f));
+ dependencies = prop;
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to load dependencies informations", e);
+ }
+ }
+ String version = dependencies.getProperty(groupId + "/" + artifactId + "/version");
+ if (version == null) {
+ throw new IllegalStateException("Unable to find dependency information for: " + groupId + "/" + artifactId + "/version");
+ }
+ return version;
+ }
+
+ protected String[] getTestFrameworkBundlesNames() {
+ return new String[] {
+ getBundle("org.apache.geronimo.specs", "geronimo-servlet_2.5_spec"),
+ getBundle("org.apache.servicemix.specs", "org.apache.servicemix.specs.jaxp-api-1.4"),
+ getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri"),
+ getBundle("org.apache.felix", "org.osgi.compendium"),
+ getBundle("org.apache.felix", "org.apache.felix.configadmin"),
+ getBundle("org.ops4j.pax.logging", "pax-logging-api"),
+ getBundle("org.ops4j.pax.logging", "pax-logging-service"),
+ getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.aopalliance"),
+ getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.asm"),
+ getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.junit"),
+ getBundle("org.springframework", "spring-beans"),
+ getBundle("org.springframework", "spring-core"),
+ getBundle("org.springframework", "spring-context"),
+ getBundle("org.springframework", "spring-aop"),
+ getBundle("org.springframework", "spring-test"),
+ getBundle("org.springframework.osgi", "spring-osgi-core"),
+ getBundle("org.springframework.osgi", "spring-osgi-io"),
+ getBundle("org.springframework.osgi", "spring-osgi-extender"),
+ getBundle("org.springframework.osgi", "spring-osgi-test"),
+ getBundle("org.springframework.osgi", "spring-osgi-annotation"),
+ getBundle("org.ops4j.pax.url", "pax-url-mvn"),
+ getBundle("org.apache.servicemix.kernel.testing", "org.apache.servicemix.kernel.testing.support"),
+ };
+ }
+
+ protected Bundle installBundle(String groupId, String artifactId, String classifier, String type) throws Exception {
+ String version = getBundleVersion(groupId, artifactId);
+ File loc = localMavenBundle(groupId, artifactId, version, classifier, type);
+ Bundle bundle = bundleContext.installBundle(loc.toURI().toString());
+ bundle.start();
+ return bundle;
+ }
+
+ protected void addFeatureRepo(String url) throws Exception {
+ if (featureInstaller == null) {
+ featureInstaller = new FeatureInstaller();
+ featureInstaller.setBundleContext(bundleContext);
+ }
+ featureInstaller.addRepository(new URI(url));
+ }
+
+ protected void installFeature(String name) throws Exception {
+ installFeature(name, FeatureImpl.DEFAULT_VERSION);
+ }
+
+ protected void installFeature(String name, String version) throws Exception {
+ if (featureInstaller == null) {
+ featureInstaller = new FeatureInstaller();
+ featureInstaller.setBundleContext(bundleContext);
+
+ }
+ featureInstaller.installFeature(name, version);
+ }
+
+ protected Resource locateBundle(String bundleId) {
+ Assert.hasText(bundleId, "bundleId should not be empty");
+
+ // parse the String
+ String[] artifactId = StringUtils.commaDelimitedListToStringArray(bundleId);
+
+ Assert.isTrue(artifactId.length >= 3, "the CSV string " + bundleId + " contains too few values");
+ // TODO: add a smarter mechanism which can handle 1 or 2 values CSVs
+ for (int i = 0; i < artifactId.length; i++) {
+ artifactId[i] = StringUtils.trimWhitespace(artifactId[i]);
+ }
+
+ File f;
+ if (artifactId.length == 3) {
+ f = localMavenBundle(artifactId[0], artifactId[1], artifactId[2], null, ArtifactLocator.DEFAULT_ARTIFACT_TYPE);
+ } else {
+ f = localMavenBundle(artifactId[0], artifactId[1], artifactId[2], null, artifactId[3]);
+ }
+ return new FileSystemResource(f);
+ }
+
+
+ protected File localMavenBundle(String groupId, String artifact, String version, String classifier, String type) {
+ String defaultHome = new File(new File(System.getProperty("user.home")), ".m2/repository").getAbsolutePath();
+ File repositoryHome = new File(System.getProperty("localRepository", defaultHome));
+
+ StringBuffer location = new StringBuffer(groupId.replace('.', '/'));
+ location.append('/');
+ location.append(artifact);
+ location.append('/');
+ location.append(getSnapshot(version));
+ location.append('/');
+ location.append(artifact);
+ location.append('-');
+ location.append(version);
+ if (classifier != null) {
+ location.append('-');
+ location.append(classifier);
+ }
+ location.append(".");
+ location.append(type);
+
+ return new File(repositoryHome, location.toString());
+ }
+
+ protected static String getSnapshot(String version) {
+ if (isTimestamped(version)) {
+ return version.substring(0, version.lastIndexOf('-', version.lastIndexOf('-') - 1)) + "-SNAPSHOT";
+ }
+ return version;
+ }
+
+ protected static boolean isTimestamped(String version) {
+ return version.matches(".+-\\d\\d\\d\\d\\d\\d\\d\\d\\.\\d\\d\\d\\d\\d\\d-\\d+");
+ }
+
+ protected static boolean isSnapshot(String version) {
+ return version.matches(".+-SNAPSHOT");
+ }
+
+ public <T> T getOsgiService(Class<T> type) {
+ return getOsgiService(type, DEFAULT_WAIT_TIME);
+ }
+
+ public <T> T getOsgiService(Class<T> type, long timeout) {
+ // translate from seconds to miliseconds
+ long time = timeout * 1000;
+
+ // use the counter to make sure the threads block
+ final Counter counter = new Counter("waitForOsgiService on bnd=" + type.getName());
+
+ counter.increment();
+
+ final List<T> services = new ArrayList<T>();
+
+ ServiceListener listener = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ if (event.getType() == ServiceEvent.REGISTERED) {
+ services.add((T) bundleContext.getService(event.getServiceReference()));
+ counter.decrement();
+ }
+ }
+ };
+
+ String filter = OsgiFilterUtils.unifyFilter(type.getName(), null);
+ OsgiListenerUtils.addServiceListener(bundleContext, listener, filter);
+
+ if (logger.isDebugEnabled())
+ logger.debug("start waiting for OSGi service=" + type.getName());
+
+ try {
+ if (counter.waitForZero(time)) {
+ logger.warn("waiting for OSGi service=" + type.getName() + " timed out");
+ throw new RuntimeException("Gave up waiting for OSGi service '" + type.getName() + "' to be created");
+ }
+ else if (logger.isDebugEnabled()) {
+ logger.debug("found OSGi service=" + type.getName());
+ }
+ return services.get(0);
+ }
+ finally {
+ // inform waiting thread
+ bundleContext.removeServiceListener(listener);
+ }
+ }
+
+ protected void checkBundleStarted(String name) {
+ assertNotNull(bundleContext);
+ for (int i = 0; i < bundleContext.getBundles().length; i++) {
+ Bundle b = bundleContext.getBundles()[i];
+ if (b.getSymbolicName().equals(name)) {
+ assertEquals("Bundle '" + name + "' is not active", Bundle.ACTIVE, b.getState());
+ return;
+ }
+ }
+ fail("Bundle '" + name + "' not found");
+ }
+
+
+}
\ No newline at end of file
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Counter.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Counter.java
new file mode 100644
index 0000000..95a3a44
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Counter.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Simple counting class which can be incremented or decremented in a
+ * synchronized manner. This class can be used as a synchronization mechanism
+ * between threads mainly though {@link #waitForZero(long)} method.
+ *
+ * The main usage of the class is to allow a master thread, to know when other
+ * threads (slaves) have passed a certain point in execution.
+ *
+ * <p/> As opposed to a Barrier or a Semaphore, this class should be used only
+ * with 1 waiting thread (a master) and any number of slave threads.
+ *
+ * <pre style="code">
+ * Thread 1:
+ * synchronized(counter) {
+ * counter.increment();
+ * thread2.start();
+ * counter.increment();
+ * thread3.start();
+ *
+ * // wait 1 second for other threads to complete
+ * counter.waitForZero(1000);
+ * }
+ *
+ * Thread 2:
+ * // do some work
+ * counter.decrement();
+ *
+ * Thread 3:
+ * // do some work
+ * counter.decrement();
+ *
+ * </pre>
+ *
+ * <p/> Mainly for usage inside the framework. All methods are thread-safe
+ * however for the master/slave pattern, synchronized blocks are recommended as
+ * multiple operations have to be executed at once.
+ *
+ * @author Costin Leau
+ *
+ */
+public class Counter {
+
+ private int counter = 0;
+
+ private static final Log log = LogFactory.getLog(Counter.class);
+
+ private final String name;
+
+ /**
+ * Create counter with a given name.
+ * @param name counter name
+ */
+ public Counter(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Increment the counter value.
+ */
+ public synchronized void increment() {
+ counter++;
+ if (log.isTraceEnabled())
+ log.trace("counter [" + name + "] incremented to " + counter);
+ }
+
+ /**
+ * Decrement the counter value.
+ */
+ public synchronized void decrement() {
+ counter--;
+ if (log.isTraceEnabled())
+ log.trace("counter [" + name + "] decremented to " + counter);
+ notifyAll();
+ }
+
+ public synchronized boolean decrementAndWait(long timeToWait) {
+ decrement();
+ if (counter > 0)
+ return waitForZero(timeToWait);
+ return true;
+ }
+
+ /**
+ * Check if the counter value is zero.
+ * @return true if value is equal or below zero, false otherwise.
+ */
+ public synchronized boolean isZero() {
+ return is(0);
+ }
+
+ public synchronized boolean is(int value) {
+ return counter == value;
+ }
+
+ /**
+ * Return the counter value.
+ *
+ * @return the counter value.
+ */
+ public synchronized int getValue() {
+ return counter;
+ }
+
+ public synchronized String toString() {
+ return "" + counter;
+ }
+
+ /**
+ * Specialized method which waits for 0. Identical to waitFor(0, waitTime).
+ *
+ * @see #waitFor(int, long)
+ * @param waitTime
+ * @return true if the waiting timed out, false otherwise
+ */
+ public synchronized boolean waitForZero(long waitTime) {
+ return waitFor(0, waitTime);
+ }
+
+ /**
+ * Wait maximum the givem amount of time, for the counter to reach the given
+ * value.. This mechanism relies on {@link Object#wait(long)} and
+ * {@link Object#notify()} mechanism to work appropriately. Please see the
+ * class javadoc for more info.
+ *
+ * <p/> This method will stop waiting and return true if the thread
+ * is interrupted.
+ *
+ * @param value the value to wait for
+ * @param waitTime the time (in miliseconds) to wait for zero value
+ * @return true if the waiting timed out, false otherwise
+ */
+ public synchronized boolean waitFor(int value, long waitTime) {
+ boolean timedout = false;
+ long remainingTime = waitTime;
+ long startTime = System.currentTimeMillis();
+
+ while (counter > value && !timedout) {
+ // start waiting
+ try {
+ this.wait(remainingTime);
+ // compute the remaining time
+ remainingTime = waitTime - (System.currentTimeMillis() - startTime);
+ timedout = remainingTime <= 0;
+ }
+ catch (InterruptedException ex) {
+ timedout = true;
+ }
+ }
+
+ return timedout;
+ }
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Feature.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Feature.java
new file mode 100644
index 0000000..56006cf
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Feature.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A feature is a list of bundles associated identified by its name.
+ */
+public interface Feature {
+
+ String getId();
+
+ String getName();
+
+ String getVersion();
+
+ List<Feature> getDependencies();
+
+ List<String> getBundles();
+
+ Map<String, Map<String, String>> getConfigurations();
+
+ void addDependency(Feature dependency);
+
+ void addBundle(String bundle);
+
+ void addConfig(String name, Map<String,String> properties);
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureImpl.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureImpl.java
new file mode 100644
index 0000000..9c8c9a2
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureImpl.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+public class FeatureImpl implements Feature {
+
+ private String id;
+ private String name;
+ private String version;
+ private List<Feature> dependencies = new ArrayList<Feature>();
+ private List<String> bundles = new ArrayList<String>();
+ private Map<String, Map<String,String>> configs = new HashMap<String, Map<String,String>>();
+ public static String SPLIT_FOR_NAME_AND_VERSION = "_split_for_name_and_version_";
+ public static String DEFAULT_VERSION = "0.0.0";
+
+ public FeatureImpl(String name) {
+ this(name, DEFAULT_VERSION);
+ }
+
+ public FeatureImpl(String name, String version) {
+ this.name = name;
+ this.version = version;
+ this.id = name + "-" + version;
+ }
+
+
+ public String getId() {
+ return id;
+ }
+
+
+ public String getName() {
+ return name;
+ }
+
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+
+ public List<Feature> getDependencies() {
+ return dependencies;
+ }
+
+ public List<String> getBundles() {
+ return bundles;
+ }
+
+ public Map<String, Map<String, String>> getConfigurations() {
+ return configs;
+ }
+
+ public void addDependency(Feature dependency) {
+ dependencies.add(dependency);
+ }
+
+ public void addBundle(String bundle) {
+ bundles.add(bundle);
+ }
+
+ public void addConfig(String name, Map<String,String> properties) {
+ configs.put(name, properties);
+ }
+
+ public String toString() {
+ String ret = getName() + SPLIT_FOR_NAME_AND_VERSION + getVersion();
+ return ret;
+ }
+
+ public static Feature valueOf(String str) {
+ if (str.indexOf(SPLIT_FOR_NAME_AND_VERSION) >= 0) {
+ String strName = str.substring(0, str.indexOf(SPLIT_FOR_NAME_AND_VERSION));
+ String strVersion = str.substring(str.indexOf(SPLIT_FOR_NAME_AND_VERSION)
+ + SPLIT_FOR_NAME_AND_VERSION.length(), str.length());
+ return new FeatureImpl(strName, strVersion);
+ } else {
+ return new FeatureImpl(str);
+ }
+
+
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FeatureImpl feature = (FeatureImpl) o;
+
+ if (!name.equals(feature.name)) return false;
+ if (!version.equals(feature.version)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result = name.hashCode();
+ result = 31 * result + version.hashCode();
+ return result;
+ }
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureInstaller.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureInstaller.java
new file mode 100644
index 0000000..d200e40
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureInstaller.java
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicemix.kernel.testing.support;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+
+public class FeatureInstaller {
+
+ private Map<URI, FeatureRepositoryImpl> repositories = new HashMap<URI, FeatureRepositoryImpl>();
+ private Map<String, Map<String, Feature>> features;
+ private BundleContext bundleContext;
+
+ public void addRepository(URI uri) throws Exception {
+ if (!repositories.values().contains(uri)) {
+ internalAddRepository(uri);
+ }
+ }
+
+ protected FeatureRepositoryImpl internalAddRepository(URI uri) throws Exception {
+ FeatureRepositoryImpl repo = new FeatureRepositoryImpl(uri);
+ repositories.put(uri, repo);
+ features = null;
+ return repo;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+
+ public void installFeature(String name, String version) throws Exception {
+ Feature f = getFeature(name, version);
+ if (f == null) {
+ throw new Exception("No feature named '" + name
+ + "' with version '" + version + "' available");
+ }
+ for (Feature dependency : f.getDependencies()) {
+ installFeature(dependency.getName(), dependency.getVersion());
+ }
+
+ Set<Long> bundles = new HashSet<Long>();
+ for (String bundleLocation : f.getBundles()) {
+ Bundle b = installBundleIfNeeded(bundleLocation);
+ bundles.add(b.getBundleId());
+ }
+ for (long id : bundles) {
+ bundleContext.getBundle(id).start();
+ }
+
+
+ }
+
+ protected Feature getFeature(String name, String version) throws Exception {
+ Map<String, Feature> versions = getFeatures().get(name);
+ if (versions == null || versions.isEmpty()) {
+ return null;
+ } else {
+ Feature feature = versions.get(version);
+ if (feature == null && FeatureImpl.DEFAULT_VERSION.equals(version)) {
+ Version latest = new Version(cleanupVersion(version));
+ for (String available : versions.keySet()) {
+ Version availableVersion = new Version(cleanupVersion(available));
+ if (availableVersion.compareTo(latest) > 0) {
+ feature = versions.get(available);
+ latest = availableVersion;
+ }
+ }
+ }
+ return feature;
+ }
+ }
+
+ protected Map<String, Map<String, Feature>> getFeatures() throws Exception {
+ if (features == null) {
+ //the outer map's key is feature name, the inner map's key is feature version
+ Map<String, Map<String, Feature>> map = new HashMap<String, Map<String, Feature>>();
+ // Two phase load:
+ // * first load dependent repositories
+ for (;;) {
+ boolean newRepo = false;
+ for (FeatureRepositoryImpl repo : listRepositories()) {
+ for (URI uri : repo.getRepositories()) {
+ if (!repositories.keySet().contains(uri)) {
+ internalAddRepository(uri);
+ newRepo = true;
+ }
+ }
+ }
+ if (!newRepo) {
+ break;
+ }
+ }
+ // * then load all features
+ for (FeatureRepositoryImpl repo : repositories.values()) {
+ for (Feature f : repo.getFeatures()) {
+ if (map.get(f.getName()) == null) {
+ Map<String, Feature> versionMap = new HashMap<String, Feature>();
+ versionMap.put(f.getVersion(), f);
+ map.put(f.getName(), versionMap);
+ } else {
+ map.get(f.getName()).put(f.getVersion(), f);
+ }
+ }
+ }
+ features = map;
+ }
+ return features;
+ }
+
+ public FeatureRepositoryImpl[] listRepositories() {
+ Collection<FeatureRepositoryImpl> repos = repositories.values();
+ return repos.toArray(new FeatureRepositoryImpl[repos.size()]);
+ }
+
+ protected Bundle installBundleIfNeeded(String bundleLocation) throws IOException, BundleException {
+ InputStream is = new BufferedInputStream(new URL(bundleLocation).openStream());
+ try {
+ is.mark(256 * 1024);
+ JarInputStream jar = new JarInputStream(is);
+ Manifest m = jar.getManifest();
+ String sn = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+ String vStr = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+ Version v = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+ for (Bundle b : bundleContext.getBundles()) {
+ if (b.getSymbolicName() != null && b.getSymbolicName().equals(sn)) {
+ vStr = (String) b.getHeaders().get(Constants.BUNDLE_VERSION);
+ Version bv = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+ if (v.equals(bv)) {
+ return b;
+ }
+ }
+ }
+ try {
+ is.reset();
+ } catch (IOException e) {
+ is.close();
+ is = new BufferedInputStream(new URL(bundleLocation).openStream());
+ }
+ return getBundleContext().installBundle(bundleLocation, is);
+ } finally {
+ is.close();
+ }
+ }
+
+ private BundleContext getBundleContext() {
+ return this.bundleContext;
+ }
+
+ /**
+ * Clean up version parameters. Other builders use more fuzzy definitions of
+ * the version syntax. This method cleans up such a version to match an OSGi
+ * version.
+ *
+ * @param version
+ * @return
+ */
+ static Pattern fuzzyVersion = Pattern.compile("(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?",
+ Pattern.DOTALL);
+ static Pattern fuzzyModifier = Pattern.compile("(\\d+[.-])*(.*)",
+ Pattern.DOTALL);
+ static public String cleanupVersion(String version) {
+ Matcher m = fuzzyVersion.matcher(version);
+ if (m.matches()) {
+ StringBuffer result = new StringBuffer();
+ String d1 = m.group(1);
+ String d2 = m.group(3);
+ String d3 = m.group(5);
+ String qualifier = m.group(7);
+
+ if (d1 != null) {
+ result.append(d1);
+ if (d2 != null) {
+ result.append(".");
+ result.append(d2);
+ if (d3 != null) {
+ result.append(".");
+ result.append(d3);
+ if (qualifier != null) {
+ result.append(".");
+ cleanupModifier(result, qualifier);
+ }
+ } else if (qualifier != null) {
+ result.append(".0.");
+ cleanupModifier(result, qualifier);
+ }
+ } else if (qualifier != null) {
+ result.append(".0.0.");
+ cleanupModifier(result, qualifier);
+ }
+ return result.toString();
+ }
+ }
+ return version;
+ }
+
+ static void cleanupModifier(StringBuffer result, String modifier) {
+ Matcher m = fuzzyModifier.matcher(modifier);
+ if (m.matches())
+ modifier = m.group(2);
+
+ for (int i = 0; i < modifier.length(); i++) {
+ char c = modifier.charAt(i);
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z') || c == '_' || c == '-')
+ result.append(c);
+ }
+ }
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureRepositoryImpl.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureRepositoryImpl.java
new file mode 100644
index 0000000..fb296bb
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureRepositoryImpl.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+
+
+/**
+ * The repository implementation.
+ */
+
+public class FeatureRepositoryImpl {
+
+ private URI uri;
+ private List<Feature> features;
+ private List<URI> repositories;
+
+ public FeatureRepositoryImpl(URI uri) {
+ this.uri = uri;
+ }
+
+
+ public URI getURI() {
+ return uri;
+ }
+
+ public URI[] getRepositories() throws Exception {
+ if (repositories == null) {
+ load();
+ }
+ return repositories.toArray(new URI[repositories.size()]);
+ }
+
+ public Feature[] getFeatures() throws Exception {
+ if (features == null) {
+ load();
+ }
+ return features.toArray(new Feature[features.size()]);
+ }
+
+ public void load() throws IOException {
+ try {
+ repositories = new ArrayList<URI>();
+ features = new ArrayList<Feature>();
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ Document doc = factory.newDocumentBuilder().parse(uri.toURL().openStream());
+ NodeList nodes = doc.getDocumentElement().getChildNodes();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+ if (!(node instanceof Element)) {
+ continue;
+ }
+ if ("repository".equals(node.getNodeName())) {
+ Element e = (Element) nodes.item(i);
+ repositories.add(new URI(e.getTextContent()));
+ } else if ("feature".equals(node.getNodeName())) {
+ Element e = (Element) nodes.item(i);
+ String name = e.getAttribute("name");
+ String version = e.getAttribute("version");
+ Feature f;
+ if (version != null && version.length() > 0) {
+ f = new FeatureImpl(name, version);
+ } else {
+ f = new FeatureImpl(name);
+ }
+
+ NodeList featureNodes = e.getElementsByTagName("feature");
+ for (int j = 0; j < featureNodes.getLength(); j++) {
+ Element b = (Element) featureNodes.item(j);
+ String dependencyFeatureVersion = b.getAttribute("version");
+ if (dependencyFeatureVersion != null && dependencyFeatureVersion.length() > 0) {
+ f.addDependency(new FeatureImpl(b.getTextContent(), dependencyFeatureVersion));
+ } else {
+ f.addDependency(new FeatureImpl(b.getTextContent()));
+ }
+ }
+ NodeList configNodes = e.getElementsByTagName("config");
+ for (int j = 0; j < configNodes.getLength(); j++) {
+ Element c = (Element) configNodes.item(j);
+ String cfgName = c.getAttribute("name");
+ String data = c.getTextContent();
+ Properties properties = new Properties();
+ properties.load(new ByteArrayInputStream(data.getBytes()));
+ Map<String, String> hashtable = new Hashtable<String, String>();
+ for (Object key : properties.keySet()) {
+ String n = key.toString();
+ hashtable.put(n, properties.getProperty(n));
+ }
+ f.addConfig(cfgName, hashtable);
+ }
+ NodeList bundleNodes = e.getElementsByTagName("bundle");
+ for (int j = 0; j < bundleNodes.getLength(); j++) {
+ Element b = (Element) bundleNodes.item(j);
+ f.addBundle(b.getTextContent());
+ }
+ features.add(f);
+ }
+ }
+ } catch (SAXException e) {
+ throw (IOException) new IOException().initCause(e);
+ } catch (ParserConfigurationException e) {
+ throw (IOException) new IOException().initCause(e);
+ } catch (URISyntaxException e) {
+ throw (IOException) new IOException().initCause(e);
+ }
+ }
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FrameworkUtil.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FrameworkUtil.java
new file mode 100644
index 0000000..e3427a9
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FrameworkUtil.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import org.apache.felix.framework.FilterImpl;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ */
+public class FrameworkUtil {
+
+ public static Filter createFilter(String f) throws InvalidSyntaxException {
+ return new FilterImpl(f);
+ }
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/SmxKernelPlatform.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/SmxKernelPlatform.java
new file mode 100644
index 0000000..eed2d5e
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/SmxKernelPlatform.java
@@ -0,0 +1,428 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.felix.framework.Felix;
+import org.apache.felix.framework.util.CompoundEnumeration;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.servicemix.kernel.main.Main;
+import org.apache.servicemix.kernel.main.spi.MainService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.springframework.osgi.test.platform.FelixPlatform;
+import org.springframework.osgi.test.platform.OsgiPlatform;
+import org.springframework.util.ClassUtils;
+
+public class SmxKernelPlatform implements OsgiPlatform {
+
+ private static final Log log = LogFactory.getLog(FelixPlatform.class);
+
+ private static final String FELIX_CONF_FILE = "config.properties";
+
+ private static final String FELIX_CONFIG_PROPERTY = "config.properties";
+
+ public final static String FRAMEWORK_STORAGE = "org.osgi.framework.storage";
+
+ private BundleContext context;
+
+ private Object platform;
+
+ private File felixStorageDir;
+
+ private Properties configurationProperties = new Properties();
+
+ protected Properties getPlatformProperties() {
+ // load Felix configuration
+ Properties props = new Properties();
+ props.putAll(getFelixConfiguration());
+ props.putAll(getLocalConfiguration());
+ return props;
+ }
+
+ public Properties getConfigurationProperties() {
+ // local properties
+ configurationProperties.putAll(getPlatformProperties());
+ // system properties
+ configurationProperties.putAll(System.getProperties());
+ return configurationProperties;
+ }
+
+ public BundleContext getBundleContext() {
+ return context;
+ }
+
+ private Set<String> getJars(Class... classes) {
+ Set<String> jars = new HashSet<String>();
+ for (Class cl : classes) {
+ String name = cl.getName().replace('.', '/') + ".class";
+ URL url = (cl.getClassLoader() != null ? cl.getClassLoader() : getClass().getClassLoader()).getResource(name);
+ String path = url.toString();
+ if (path.startsWith("jar:")) {
+ path = path.substring(0, path.indexOf('!'));
+ } else {
+ path = path.substring(0, path.indexOf(name));
+ }
+ jars.add(path);
+ }
+ return jars;
+ }
+
+ public void start() throws Exception {
+ Set<String> jars = getJars(Felix.class);
+ ClassLoader classLoader = new GuardClassLoader(toURLs(jars.toArray(new String[jars.size()])), null);
+
+ BundleActivator activator = new BundleActivator() {
+ private ServiceRegistration registration;
+
+ public void start(BundleContext context) {
+ registration = context.registerService(MainService.class.getName(), new MainService() {
+ public String[] getArgs() {
+ return new String[0];
+ }
+ public int getExitCode() {
+ return 0;
+ }
+ public void setExitCode(int exitCode) {
+ }
+ }, null);
+ }
+
+ public void stop(BundleContext context) {
+ registration.unregister();
+ }
+ };
+ List<BundleActivator> activations = new ArrayList<BundleActivator>();
+ activations.add(activator);
+
+ Properties props = getConfigurationProperties();
+ props.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, activations);
+
+ Thread.currentThread().setContextClassLoader(classLoader);
+ Class cl = classLoader.loadClass(Felix.class.getName());
+ Constructor cns = cl.getConstructor(Map.class);
+ platform = cns.newInstance(props);
+ platform.getClass().getMethod("start").invoke(platform);
+
+ Bundle systemBundle = (Bundle) platform;
+
+ // call getBundleContext
+ final Method getContext = systemBundle.getClass().getMethod("getBundleContext", null);
+
+ AccessController.doPrivileged(new PrivilegedAction() {
+
+ public Object run() {
+ getContext.setAccessible(true);
+ return null;
+ }
+ });
+ context = (BundleContext) getContext.invoke(systemBundle, null);
+ }
+
+ public void stop() throws Exception {
+ try {
+ platform.getClass().getMethod("stop").invoke(platform);
+ }
+ finally {
+ // remove cache folder
+ delete(felixStorageDir);
+ }
+ }
+
+ public String toString() {
+ return getClass().getName();
+ }
+
+ File createTempDir(String suffix) {
+ if (suffix == null)
+ suffix = "osgi";
+ File tempFileName;
+
+ try {
+ tempFileName = File.createTempFile("org.sfw.osgi", suffix);
+ }
+ catch (IOException ex) {
+ if (log.isWarnEnabled()) {
+ log.warn("Could not create temporary directory, returning a temp folder inside the current folder", ex);
+ }
+ return new File("./tmp-test");
+ }
+
+ tempFileName.delete(); // we want it to be a directory...
+ File tempFolder = new File(tempFileName.getAbsolutePath());
+ tempFolder.mkdir();
+ return tempFolder;
+ }
+
+ /**
+ * Configuration settings for the OSGi test run.
+ *
+ * @return
+ */
+ private Properties getLocalConfiguration() {
+ Properties props = new Properties();
+ felixStorageDir = createTempDir("felix");
+ props.setProperty(FRAMEWORK_STORAGE, this.felixStorageDir.getAbsolutePath());
+ if (log.isTraceEnabled())
+ log.trace("felix storage dir is " + felixStorageDir.getAbsolutePath());
+
+ return props;
+ }
+
+ /**
+ * Loads Felix config.properties.
+ *
+ * <strong>Note</strong> the current implementation uses Felix's Main class
+ * to resolve placeholders as opposed to loading the properties manually
+ * (through JDK's Properties class or Spring's PropertiesFactoryBean).
+ *
+ * @return
+ */
+ // TODO: this method should be removed once Felix 1.0.2 is released
+ private Properties getFelixConfiguration() {
+ String location = "/".concat(ClassUtils.classPackageAsResourcePath(getClass())).concat("/").concat(FELIX_CONF_FILE);
+ URL url = getClass().getResource(location);
+ if (url == null)
+ throw new RuntimeException("cannot find felix configuration properties file:" + location);
+
+ // used with Main
+ System.getProperties().setProperty(FELIX_CONFIG_PROPERTY, url.toExternalForm());
+
+ // load config.properties (use Felix's Main for resolving placeholders)
+ Properties props = new Properties();
+ InputStream is = null;
+ try {
+ is = url.openConnection().getInputStream();
+ props.load(is);
+ is.close();
+ }
+ catch (FileNotFoundException ex) {
+ // Ignore file not found.
+ }
+ catch (Exception ex) {
+ System.err.println("Main: Error loading system properties from " + url);
+ System.err.println("Main: " + ex);
+ try {
+ if (is != null) is.close();
+ }
+ catch (IOException ex2) {
+ // Nothing we can do.
+ }
+ return null;
+ }
+ // Perform variable substitution for system properties.
+ for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
+ String name = (String) e.nextElement();
+ props.setProperty(name, Main.substVars(props.getProperty(name), name, null, props));
+ }
+ return props;
+ }
+
+ /**
+ * Delete the given file (can be a simple file or a folder).
+ *
+ * @param file the file to be deleted
+ * @return if the deletion succeded or not
+ */
+ public static boolean delete(File file) {
+
+ // bail out quickly
+ if (file == null)
+ return false;
+
+ // recursively delete children file
+ boolean success = true;
+
+ if (file.isDirectory()) {
+ String[] children = file.list();
+ for (int i = 0; i < children.length; i++) {
+ success &= delete(new File(file, children[i]));
+ }
+ }
+
+ // The directory is now empty so delete it
+ return (success &= file.delete());
+ }
+
+ private static URL[] toURLs(String[] jars) throws MalformedURLException {
+ URL[] urls = new URL[jars.length];
+ for (int i = 0; i < urls.length; i++) {
+ String s = jars[i];
+ if (s.startsWith("jar:")) {
+ s = s.substring("jar:".length());
+ }
+ urls[i] = new URL(s);
+ }
+ return urls;
+ }
+
+ public class GuardClassLoader extends URLClassLoader {
+ private Set<String> bootDelegationPackages = new HashSet<String>();
+ private Set<String> packages = new HashSet<String>();
+ private List<ClassLoader> parents = new ArrayList<ClassLoader>();
+
+ public GuardClassLoader(URL[] urls, List<String> additionalPackages) throws MalformedURLException {
+ super(urls, SmxKernelPlatform.class.getClassLoader());
+ Properties props = getConfigurationProperties();
+ String prop = props.getProperty("org.osgi.framework.system.packages");
+ String[] ps = prop.split(",");
+ for (String p : ps) {
+ String[] spack = p.split(";");
+ for (String sp : spack) {
+ sp = sp.trim();
+ if (!sp.startsWith("version")) {
+ packages.add(sp);
+ }
+ }
+ }
+ if (additionalPackages != null) {
+ packages.addAll(additionalPackages);
+ }
+ prop = props.getProperty("org.osgi.framework.bootdelegation");
+ ps = prop.split(",");
+ for (String p : ps) {
+ p = p.trim();
+ if (p.endsWith("*")) {
+ p = p.substring(0, p.length() - 1);
+ }
+ bootDelegationPackages.add(p);
+ }
+ ClassLoader cl = getParent();
+ while (cl != null) {
+ parents.add(0, cl);
+ cl = cl.getParent();
+ }
+ //System.err.println("Boot packages: " + packages);
+ }
+
+ protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ //System.err.println("Loading class: " + name);
+ Class c = findLoadedClass(name);
+ if (c == null) {
+ String pkg = name.substring(0, name.lastIndexOf('.'));
+ boolean match = name.startsWith("java.") || packages.contains(pkg);
+ if (!match) {
+ for (String p : bootDelegationPackages) {
+ if (pkg.startsWith(p)) {
+ match = true;
+ break;
+ }
+ }
+ }
+ if (match) {
+ for (ClassLoader cl : parents) {
+ try {
+ c = cl.loadClass(name);
+ //System.err.println("Class loaded from: " + cl.getResource(name.replace('.', '/') + ".class"));
+ break;
+ } catch (ClassNotFoundException e) {
+ }
+ }
+ if (c == null) {
+ throw new ClassNotFoundException(name);
+ }
+ //c = getParent().loadClass(name);
+ } else {
+ c = findClass(name);
+ }
+ }
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+
+ public URL getResource(String name) {
+ //System.err.println("GetResource: " + name);
+ URL url = getParent().getResource(name);
+ if (url != null && url.toString().startsWith("file:")) {
+ return url;
+ }
+ url = findResource(name);
+ System.err.println("Resource " + name + " found at " + url);
+ return url;
+ /*
+ URL u = getParent().getResource(name);
+ if (u != null) {
+ String path = u.toString();
+ int idx = path.indexOf('!');
+ if (idx > 0) {
+ path = path.substring(0, idx);
+ if (!jars.contains(path)) {
+ return null;
+ }
+ } else {
+ idx = 0;
+ }
+ }
+ return u;
+ */
+ }
+
+ public Enumeration<URL> getResources(final String name) throws IOException {
+ //System.err.println("GetResources: " + name);
+ Enumeration[] tmp = new Enumeration[2];
+ final Enumeration<URL> e = getParent().getResources(name);
+ tmp[0] = new Enumeration<URL>() {
+ URL next = null;
+ public boolean hasMoreElements() {
+ while (next == null && e.hasMoreElements()) {
+ next = e.nextElement();
+ String path = next.toString();
+ if (!path.startsWith("file:")) {
+ next = null;
+ }
+ }
+ return next != null;
+ }
+ public URL nextElement() {
+ return next;
+ }
+ };
+ tmp[1] = findResources(name);
+ return new CompoundEnumeration(tmp) {
+ public Object nextElement() {
+ Object next = super.nextElement();
+ System.err.println("Resources " + name + " found at " + next);
+ return next;
+ }
+ };
+ }
+ }
+}
diff --git a/karaf/testing/support/src/test/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTestTest.java b/karaf/testing/support/src/test/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTestTest.java
new file mode 100644
index 0000000..9acba05
--- /dev/null
+++ b/karaf/testing/support/src/test/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTestTest.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import junit.framework.TestCase;
+
+
+public class AbstractIntegrationTestTest extends TestCase {
+
+ public void testSnapshotVersion() {
+ assertTrue(AbstractIntegrationTest.isTimestamped("0.9.0-20070713.230317-1"));
+ assertTrue(AbstractIntegrationTest.isSnapshot("0.9.0-SNAPSHOT"));
+ assertFalse(AbstractIntegrationTest.isSnapshot("0.9.0"));
+ assertEquals("0.9.0-SNAPSHOT", AbstractIntegrationTest.getSnapshot("0.9.0-20070713.230317-1"));
+ assertEquals("0.9.0", "0.9.0");
+ }
+
+}