FELIX-1107, FELIX-1109, FELIX-1110: refactor the deployer into its own module, add a blueprint deployer and extract the features deployer in its own module
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@770120 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/deployer/blueprint/pom.xml b/karaf/deployer/blueprint/pom.xml
new file mode 100644
index 0000000..2b0bcf5
--- /dev/null
+++ b/karaf/deployer/blueprint/pom.xml
@@ -0,0 +1,74 @@
+<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.deployer</groupId>
+ <artifactId>deployer</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.servicemix.kernel.deployer</groupId>
+ <artifactId>org.apache.servicemix.kernel.deployer.blueprint</artifactId>
+ <packaging>bundle</packaging>
+ <version>1.2.0-SNAPSHOT</version>
+ <name>Apache ServiceMix Kernel :: Blueprint Deployer</name>
+
+ <description>This deployer transforms a plain blueprint xml file to a deployable bundle</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.kernel.deployer</groupId>
+ <artifactId>org.apache.servicemix.kernel.deployer.filemonitor</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+ <Private-Package>org.apache.servicemix.kernel.deployer.blueprint</Private-Package>
+ <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintDeploymentListener.java b/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintDeploymentListener.java
new file mode 100644
index 0000000..13ef072
--- /dev/null
+++ b/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintDeploymentListener.java
@@ -0,0 +1,81 @@
+/**
+ *
+ * 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.deployer.blueprint;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.deployer.filemonitor.DeploymentListener;
+
+/**
+ * A deployment listener that listens for spring xml applications
+ * and creates bundles for these.
+ */
+public class BlueprintDeploymentListener implements DeploymentListener {
+
+
+ private static final Log LOGGER = LogFactory.getLog(BlueprintDeploymentListener.class);
+
+ private DocumentBuilderFactory dbf;
+
+ public boolean canHandle(File artifact) {
+ try {
+ if (artifact.isFile() && artifact.getName().endsWith(".xml")) {
+ Document doc = parse(artifact);
+ String name = doc.getDocumentElement().getLocalName();
+ String uri = doc.getDocumentElement().getNamespaceURI();
+ if ("blueprint".equals(name) && "http://www.osgi.org/xmlns/blueprint/v1.0.0".equals(uri)) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.error("Unable to parse deployed file " + artifact.getAbsolutePath(), e);
+ }
+ return false;
+ }
+
+ public File handle(File artifact, File tmpDir) {
+ try {
+ File destFile = new File(tmpDir, artifact.getName() + ".jar");
+ FileOutputStream os = new FileOutputStream(destFile);
+ BlueprintTransformer.transform(artifact.toURL(), os);
+ os.close();
+ return destFile;
+ } catch (Exception e) {
+ LOGGER.error("Unable to build blueprint application bundle", e);
+ return null;
+ }
+ }
+
+ protected Document parse(File artifact) throws Exception {
+ if (dbf == null) {
+ dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ }
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ return db.parse(artifact);
+ }
+
+}
diff --git a/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintTransformer.java b/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintTransformer.java
new file mode 100644
index 0000000..f466527
--- /dev/null
+++ b/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintTransformer.java
@@ -0,0 +1,248 @@
+/**
+ *
+ * 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.deployer.blueprint;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.osgi.framework.Constants;
+
+public class BlueprintTransformer {
+
+ static Transformer transformer;
+ static DocumentBuilderFactory dbf;
+ static TransformerFactory tf;
+
+
+ public static void transform(URL url, OutputStream os) throws Exception {
+ // Build dom document
+ Document doc = parse(url);
+ // Heuristicly retrieve name and version
+ String name = url.getPath();
+ int idx = name.lastIndexOf('/');
+ if (idx >= 0) {
+ name = name.substring(idx + 1);
+ }
+ String[] str = extractNameVersionType(name);
+ // Create manifest
+ Manifest m = new Manifest();
+ m.getMainAttributes().putValue("Manifest-Version", "2");
+ m.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+ m.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, str[0]);
+ m.getMainAttributes().putValue(Constants.BUNDLE_VERSION, str[1]);
+ String importPkgs = getImportPackages(analyze(new DOMSource(doc)));
+ if (importPkgs != null && importPkgs.length() > 0) {
+ m.getMainAttributes().putValue(Constants.IMPORT_PACKAGE, importPkgs);
+ }
+ m.getMainAttributes().putValue(Constants.DYNAMICIMPORT_PACKAGE, "*");
+ // Extract manifest entries from the DOM
+ NodeList l = doc.getElementsByTagName("manifest");
+ if (l != null) {
+ for (int i = 0; i < l.getLength(); i++) {
+ Element e = (Element) l.item(i);
+ String text = e.getTextContent();
+ Properties props = new Properties();
+ props.load(new ByteArrayInputStream(text.trim().getBytes()));
+ Enumeration en = props.propertyNames();
+ while (en.hasMoreElements()) {
+ String k = (String) en.nextElement();
+ String v = props.getProperty(k);
+ m.getMainAttributes().putValue(k, v);
+ }
+ e.getParentNode().removeChild(e);
+ }
+ }
+
+ JarOutputStream out = new JarOutputStream(os);
+ ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
+ out.putNextEntry(e);
+ m.write(out);
+ out.closeEntry();
+ e = new ZipEntry("OSGI-INF/");
+ out.putNextEntry(e);
+ e = new ZipEntry("OSGI-INF/blueprint/");
+ out.putNextEntry(e);
+ out.closeEntry();
+ e = new ZipEntry("OSGI-INF/blueprint/" + name);
+ out.putNextEntry(e);
+ // Copy the new DOM
+ if (tf == null) {
+ tf = TransformerFactory.newInstance();
+ }
+ tf.newTransformer().transform(new DOMSource(doc), new StreamResult(out));
+ out.closeEntry();
+ out.close();
+ }
+
+ private static final String DEFAULT_VERSION = "0.0.0";
+
+ private static final Pattern ARTIFACT_MATCHER = Pattern.compile("(.+)(?:-(\\d+)(?:\\.(\\d+)(?:\\.(\\d+))?)?(?:[^a-zA-Z0-9](.*))?)(?:\\.([^\\.]+))", Pattern.DOTALL);
+ private static final Pattern FUZZY_MODIFIDER = Pattern.compile("(?:\\d+[.-])*(.*)", Pattern.DOTALL);
+
+ public static String[] extractNameVersionType(String url) {
+ Matcher m = ARTIFACT_MATCHER.matcher(url);
+ if (!m.matches()) {
+ return new String[] { url, DEFAULT_VERSION };
+ }
+ else {
+ //System.err.println(m.groupCount());
+ //for (int i = 1; i <= m.groupCount(); i++) {
+ // System.err.println("Group " + i + ": " + m.group(i));
+ //}
+
+ StringBuffer v = new StringBuffer();
+ String d1 = m.group(1);
+ String d2 = m.group(2);
+ String d3 = m.group(3);
+ String d4 = m.group(4);
+ String d5 = m.group(5);
+ String d6 = m.group(6);
+ if (d2 != null) {
+ v.append(d2);
+ if (d3 != null) {
+ v.append('.');
+ v.append(d3);
+ if (d4 != null) {
+ v.append('.');
+ v.append(d4);
+ if (d5 != null) {
+ v.append(".");
+ cleanupModifier(v, d5);
+ }
+ } else if (d5 != null) {
+ v.append(".0.");
+ cleanupModifier(v, d5);
+ }
+ } else if (d5 != null) {
+ v.append(".0.0.");
+ cleanupModifier(v, d5);
+ }
+ }
+ return new String[] { d1, v.toString(), d6 };
+ }
+ }
+
+ private static void cleanupModifier(StringBuffer result, String modifier) {
+ Matcher m = FUZZY_MODIFIDER.matcher(modifier);
+ if (m.matches()) {
+ modifier = m.group(1);
+ }
+ 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);
+ }
+ }
+ }
+
+ public static Set<String> analyze(Source source) throws Exception {
+ if (transformer == null) {
+ if (tf == null) {
+ tf = TransformerFactory.newInstance();
+ }
+ Source s = new StreamSource(BlueprintTransformer.class.getResourceAsStream("extract.xsl"));
+ transformer = tf.newTransformer(s);
+ }
+
+ Set<String> refers = new TreeSet<String>();
+
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ Result r = new StreamResult(bout);
+ transformer.transform(source, r);
+
+ ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+ bout.close();
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(bin));
+
+ String line = br.readLine();
+ while (line != null) {
+ line = line.trim();
+ if (line.length() > 0) {
+ String parts[] = line.split("\\s*,\\s*");
+ for (int i = 0; i < parts.length; i++) {
+ int n = parts[i].lastIndexOf('.');
+ if (n > 0) {
+ refers.add(parts[i].substring(0, n));
+ }
+ }
+ }
+ line = br.readLine();
+ }
+ br.close();
+ return refers;
+ }
+
+ protected static String getImportPackages(Set<String> packages) {
+ StringBuilder sb = new StringBuilder();
+ for (String pkg : packages) {
+ if (sb.length() > 0) {
+ sb.append(",");
+ }
+ sb.append(pkg);
+ }
+ return sb.toString();
+ }
+
+ protected static Document parse(URL url) throws Exception {
+ if (dbf == null) {
+ dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ }
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ return db.parse(url.toString());
+ }
+
+ protected static void copyInputStream(InputStream in, OutputStream out) throws Exception {
+ byte[] buffer = new byte[4096];
+ int len = in.read(buffer);
+ while (len >= 0) {
+ out.write(buffer, 0, len);
+ len = in.read(buffer);
+ }
+ }
+}
diff --git a/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintURLHandler.java b/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintURLHandler.java
new file mode 100644
index 0000000..a03ecae
--- /dev/null
+++ b/karaf/deployer/blueprint/src/main/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintURLHandler.java
@@ -0,0 +1,97 @@
+/**
+ *
+ * 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.deployer.blueprint;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.service.url.AbstractURLStreamHandlerService;
+
+/**
+ * A URL handler that will transform a JBI artifact to an OSGi bundle
+ * on the fly. Needs to be registered in the OSGi registry.
+ */
+public class BlueprintURLHandler extends AbstractURLStreamHandlerService {
+
+ private static Log logger = LogFactory.getLog(BlueprintURLHandler.class);
+
+ private static String SYNTAX = "blueprint: bp-xml-uri";
+
+ private URL blueprintXmlURL;
+
+ /**
+ * Open the connection for the given URL.
+ *
+ * @param url the url from which to open a connection.
+ * @return a connection on the specified URL.
+ * @throws IOException if an error occurs or if the URL is malformed.
+ */
+ @Override
+ public URLConnection openConnection(URL url) throws IOException {
+ if (url.getPath() == null || url.getPath().trim().length() == 0) {
+ throw new MalformedURLException ("Path can not be null or empty. Syntax: " + SYNTAX );
+ }
+ blueprintXmlURL = new URL(url.getPath());
+
+ logger.debug("Spring xml URL is: [" + blueprintXmlURL + "]");
+ return new Connection(url);
+ }
+
+ public URL getBlueprintXmlURL() {
+ return blueprintXmlURL;
+ }
+
+ public class Connection extends URLConnection {
+
+ public Connection(URL url) {
+ super(url);
+ }
+
+ @Override
+ public void connect() throws IOException {
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ try {
+ final File f = File.createTempFile("smx", "xml");
+ FileOutputStream os = new FileOutputStream(f);
+ BlueprintTransformer.transform(blueprintXmlURL, os);
+ os.close();
+ return new FileInputStream(f) {
+ public void close() throws IOException {
+ super.close();
+ f.delete();
+ }
+ };
+ } catch (Exception e) {
+ logger.error("Error opening spring xml url", e);
+ throw (IOException) new IOException("Error opening spring xml url").initCause(e);
+ }
+ }
+ }
+
+}
diff --git a/karaf/deployer/blueprint/src/main/resources/META-INF/spring/blueprint-deployer.xml b/karaf/deployer/blueprint/src/main/resources/META-INF/spring/blueprint-deployer.xml
new file mode 100644
index 0000000..bb3e430
--- /dev/null
+++ b/karaf/deployer/blueprint/src/main/resources/META-INF/spring/blueprint-deployer.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:osgi="http://www.springframework.org/schema/osgi"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/util
+ http://www.springframework.org/schema/util/spring-util.xsd
+ http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+ <bean id="blueprintDeploymentListener" class="org.apache.servicemix.kernel.deployer.blueprint.BlueprintDeploymentListener">
+
+ </bean>
+
+ <osgi:service ref="blueprintDeploymentListener">
+ <osgi:interfaces>
+ <value>org.apache.servicemix.kernel.deployer.filemonitor.DeploymentListener</value>
+ </osgi:interfaces>
+ </osgi:service>
+
+ <bean id="blueprintHandler" class="org.apache.servicemix.kernel.deployer.blueprint.BlueprintURLHandler" />
+
+ <osgi:service ref="blueprintHandler" interface="org.osgi.service.url.URLStreamHandlerService">
+ <osgi:service-properties>
+ <entry key="url.handler.protocol" value="blueprint"/>
+ </osgi:service-properties>
+ </osgi:service>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/deployer/blueprint/src/main/resources/org/apache/servicemix/kernel/deployer/blueprint/extract.xsl b/karaf/deployer/blueprint/src/main/resources/org/apache/servicemix/kernel/deployer/blueprint/extract.xsl
new file mode 100644
index 0000000..2c8c291
--- /dev/null
+++ b/karaf/deployer/blueprint/src/main/resources/org/apache/servicemix/kernel/deployer/blueprint/extract.xsl
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <xsl:output method="text" />
+
+ <xsl:template match="/">
+
+ <!-- Match all attributes that holds a class or a comma delimited
+ list of classes and print them -->
+
+ <xsl:for-each select="
+ //bp:*/@class
+ | //bp:*/@type
+ | //bp:*/@value-type
+ | //bp:*/@key-type
+ | //bp:*/bp:interfaces/bp:value/text()
+ ">
+ <xsl:value-of select="." />
+ <xsl:text>
+ </xsl:text>
+ </xsl:for-each>
+
+ <!-- This seems some magic to get extra imports? -->
+
+ </xsl:template>
+
+
+</xsl:stylesheet>
+
diff --git a/karaf/deployer/blueprint/src/test/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintDeploymentListenerTest.java b/karaf/deployer/blueprint/src/test/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintDeploymentListenerTest.java
new file mode 100644
index 0000000..6ab2c33
--- /dev/null
+++ b/karaf/deployer/blueprint/src/test/java/org/apache/servicemix/kernel/deployer/blueprint/BlueprintDeploymentListenerTest.java
@@ -0,0 +1,84 @@
+/**
+ *
+ * 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.deployer.blueprint;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.jar.JarInputStream;
+
+import javax.xml.transform.dom.DOMSource;
+
+import junit.framework.TestCase;
+
+public class BlueprintDeploymentListenerTest extends TestCase {
+
+ public void testPackagesExtraction() throws Exception {
+ BlueprintDeploymentListener l = new BlueprintDeploymentListener();
+ File f = new File(getClass().getClassLoader().getResource("test.xml").toURI());
+ Set<String> pkgs = BlueprintTransformer.analyze(new DOMSource(BlueprintTransformer.parse(f.toURL())));
+ assertNotNull(pkgs);
+ assertEquals(2, pkgs.size());
+ Iterator<String> it = pkgs.iterator();
+ assertEquals("java.lang", it.next());
+ assertEquals("org.apache.geronimo.blueprint.sample", it.next());
+ }
+
+ public void testCustomManifest() throws Exception {
+ File f = File.createTempFile("smx", ".jar");
+ try {
+ OutputStream os = new FileOutputStream(f);
+ BlueprintTransformer.transform(getClass().getClassLoader().getResource("test.xml"), os);
+ os.close();
+ InputStream is = new FileInputStream(f);
+ JarInputStream jar = new JarInputStream(is);
+ jar.getManifest().write(System.err);
+ is.close();
+ } finally {
+ f.delete();
+ }
+ }
+
+ public void testVersions() {
+ assertVersion("org.apache.servicemix.bundles.ant-1.7.0-1.0-m3-SNAPSHOT.jar",
+ "org.apache.servicemix.bundles.ant-1.7.0", "1.0.0.m3-SNAPSHOT", "jar");
+ assertVersion("org.apache.activemq.core-1.0-SNAPSHOT.xml",
+ "org.apache.activemq.core", "1.0.0.SNAPSHOT", "xml");
+ assertVersion("org.apache.activemq.core-1.0.0-SNAPSHOT.xml",
+ "org.apache.activemq.core", "1.0.0.SNAPSHOT", "xml");
+ assertVersion("org.apache.activemq.core-1.0.0.xml",
+ "org.apache.activemq.core", "1.0.0", "xml");
+ assertVersion("geronimo-servlet_2.5_spec-1.1.2.jar",
+ "geronimo-servlet_2.5_spec", "1.1.2", "jar");
+ assertVersion("spring-aop-2.5.1.jar",
+ "spring-aop", "2.5.1", "jar");
+ }
+
+ private void assertVersion(String s, String... expectedParts) {
+ String[] parts = BlueprintTransformer.extractNameVersionType(s);
+ assertEquals(expectedParts.length, parts.length);
+ for (int i = 0; i < expectedParts.length; i++) {
+ assertEquals(expectedParts[i], parts[i]);
+ }
+ }
+
+}
diff --git a/karaf/deployer/blueprint/src/test/resources/test.xml b/karaf/deployer/blueprint/src/test/resources/test.xml
new file mode 100644
index 0000000..3411d48
--- /dev/null
+++ b/karaf/deployer/blueprint/src/test/resources/test.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:cm="http://www.osgi.org/xmlns/blueprint-cm/v1.0.0"
+ default-availability="optional">
+
+ <type-converters>
+ <bean id="converter1" class="org.apache.geronimo.blueprint.sample.DateTypeConverter">
+ <property name="format" value="yyyy.MM.dd"/>
+ </bean>
+ <bean id="converter2" class="org.apache.geronimo.blueprint.sample.CurrencyTypeConverter"/>
+
+ <cm:property-placeholder id="property-placeholder" persistent-id="blueprint-sample">
+ <cm:default-properties>
+ <cm:property name="key.b" value="-1"/>
+ </cm:default-properties>
+ </cm:property-placeholder>
+ </type-converters>
+
+ <bean id="foo" class="org.apache.geronimo.blueprint.sample.Foo" init-method="init" destroy-method="destroy">
+ <property name="a" value="5" />
+ <property name="b" value="${key.b}" />
+ <property name="bar" ref="bar" />
+ <property name="currency">
+ <value>PLN</value>
+ </property>
+ <property name="date">
+ <value>2009.04.17</value>
+ </property>
+ </bean>
+
+ <bean id="bar" class="org.apache.geronimo.blueprint.sample.Bar">
+ <property name="value"><value>Hello FooBar</value></property>
+ <property name="context" ref="bundleContext"/>
+ <property name="list">
+ <list>
+ <value>a list element</value>
+ <value type = "java.lang.Integer">5</value>
+ </list>
+ </property>
+ </bean>
+
+ <service ref="foo" auto-export="all-classes">
+ <service-properties>
+ <entry key="key" value="value"/>
+ </service-properties>
+ <registration-listener ref="fooRegistrationListener"
+ registration-method="serviceRegistered"
+ unregistration-method="serviceUnregistered"/>
+ </service>
+
+ <bean id="fooRegistrationListener" class="org.apache.geronimo.blueprint.sample.FooRegistrationListener"/>
+
+ <reference id="ref" interface="org.apache.geronimo.blueprint.sample.Foo">
+ </reference>
+
+ <reference id="ref2" interface="org.apache.geronimo.blueprint.sample.InterfaceA" timeout="100">
+ <listener bind-method="bind" unbind-method="unbind" ref="bindingListener" />
+ </reference>
+
+ <bean id="bindingListener" class="org.apache.geronimo.blueprint.sample.BindingListener"/>
+
+ <ref-list id="ref-list" interface="org.apache.geronimo.blueprint.sample.InterfaceA">
+ <listener bind-method="bind" unbind-method="unbind" ref="listBindingListener" />
+ </ref-list>
+
+ <bean id="listBindingListener" class="org.apache.geronimo.blueprint.sample.BindingListener"/>
+
+</blueprint>
+