Introduce OSGi Factory
authorMathieu Baudier <mbaudier@argeo.org>
Mon, 19 Aug 2013 15:07:48 +0000 (15:07 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Mon, 19 Aug 2013 15:07:48 +0000 (15:07 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@6396 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

runtime/org.argeo.slc.repo/pom.xml
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ArtifactIndexer.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/JarFileIndexer.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/OsgiFactory.java [new file with mode: 0644]
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/BndWrapper.java [new file with mode: 0644]
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/DistributionWrapper.java [new file with mode: 0644]
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/OsgiFactoryImpl.java [new file with mode: 0644]

index 9bcd679cf183cb1d54d57982f89c5604cdfd489b..3231ff7cb859763d9d1312bf8067d697b198e500 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<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">
+<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">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <groupId>org.argeo.slc</groupId>
                </dependency>
 
                <!-- Third party -->
-               <dependency>
-                       <groupId>org.argeo.tp</groupId>
-                       <artifactId>org.eclipse.osgi</artifactId>
-               </dependency>
                <dependency>
                        <groupId>org.argeo.tp</groupId>
                        <artifactId>org.apache.commons.io</artifactId>
                        <groupId>org.argeo.tp</groupId>
                        <artifactId>javax.servlet</artifactId>
                </dependency>
+
+               <!-- OSGi -->
+               <dependency>
+                       <groupId>org.argeo.tp</groupId>
+                       <artifactId>biz.aQute.bndlib</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.tp</groupId>
+                       <artifactId>org.eclipse.osgi</artifactId>
+                       <scope>provided</scope>
+               </dependency>
+
        </dependencies>
 </project>
\ No newline at end of file
index acb05b48395206f615efe3bb1308524faee1df95..462739c7d3736274083ba11960cb8ed242003fd3 100644 (file)
@@ -52,6 +52,9 @@ public class ArtifactIndexer implements NodeIndexer {
        public void index(Node fileNode) {
                Artifact artifact = null;
                try {
+                       if(!support(fileNode.getPath()))
+                               return;
+                       
                        if (!fileNode.isNodeType(NodeType.NT_FILE))
                                return;
 
index 328d4c560ec67f26a89bb2a9b8ded00ec9a65bb0..d3abf9bad0c52434c9753e8a2fbc00c0914c1bc3 100644 (file)
@@ -62,6 +62,9 @@ public class JarFileIndexer implements NodeIndexer, SlcNames {
                ByteArrayInputStream bi = null;
                Binary manifestBinary = null;
                try {
+                       if(!support(fileNode.getPath()))
+                               return;
+                       
                        if (!fileNode.isNodeType(NodeType.NT_FILE))
                                return;
 
diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/OsgiFactory.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/OsgiFactory.java
new file mode 100644 (file)
index 0000000..b2299a7
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.slc.repo;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+/** OSGi Factory */
+public interface OsgiFactory {
+       public Session openJavaSession() throws RepositoryException;
+
+       public Session openDistSession() throws RepositoryException;
+
+       public void indexNode(Node node);
+
+       /**
+        * Provide access to a third party archive in the 'dist' repository,
+        * downloading it if it is not available.
+        */
+       public Node getDist(Session distSession, String uri)
+                       throws RepositoryException;
+}
diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/BndWrapper.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/BndWrapper.java
new file mode 100644 (file)
index 0000000..00308a2
--- /dev/null
@@ -0,0 +1,116 @@
+package org.argeo.slc.repo.osgi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+import java.util.jar.Manifest;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+import org.osgi.framework.Version;
+
+import aQute.lib.osgi.Builder;
+import aQute.lib.osgi.Constants;
+import aQute.lib.osgi.Jar;
+
+/** Utilities around the BND library, which manipulates OSI meta-data. */
+public class BndWrapper implements Constants {
+       private final static Log log = LogFactory.getLog(BndWrapper.class);
+
+       private String bsn;
+       private String version;
+
+       public void wrapJar(Properties properties, InputStream in, OutputStream out) {
+               Builder b = new Builder();
+               try {
+                       Jar jar = new Jar(null, in);
+
+                       Manifest sourceManifest = jar.getManifest();
+                       String sourceVersion = sourceManifest.getMainAttributes().getValue(
+                                       BUNDLE_VERSION);
+                       Version versionToUse;
+                       if (version == null && sourceVersion == null) {
+                               throw new SlcException("A bundle version must be defined.");
+                       } else if (version == null && sourceVersion != null) {
+                               versionToUse = new Version(sourceVersion);
+                       } else if (version != null && sourceVersion == null) {
+                               versionToUse = new Version(version);
+                       } else {// both set
+                               versionToUse = new Version(version);
+                               Version sv = new Version(sourceVersion);
+                               if (versionToUse.getMajor() != sv.getMajor()
+                                               || versionToUse.getMinor() != sv.getMinor()
+                                               || versionToUse.getMicro() != sv.getMicro()) {
+                                       log.warn("The new version ("
+                                                       + versionToUse
+                                                       + ") is not consistant with the wrapped bundle version ("
+                                                       + sv + ")");
+                               }
+                       }
+
+                       properties.setProperty(BUNDLE_SYMBOLICNAME, bsn);
+                       properties.setProperty(BUNDLE_VERSION, versionToUse.toString());
+
+                       // b.addIncluded(jarFile);
+                       b.addClasspath(jar);
+
+                       b.setProperties(properties);
+
+                       Jar newJar = b.build();
+                       newJar.write(out);
+               } catch (Exception e) {
+                       throw new SlcException("Cannot wrap jar", e);
+               } finally {
+                       b.close();
+               }
+
+       }
+
+       public void setBsn(String bsn) {
+               this.bsn = bsn;
+       }
+
+       public String getBsn() {
+               return bsn;
+       }
+
+       public void setVersion(String version) {
+               this.version = version;
+       }
+
+       public String getVersion() {
+               return version;
+       }
+
+       public static void main(String[] args) {
+               BndWrapper bndWrapper = new BndWrapper();
+               bndWrapper.setBsn("org.slf4j");
+
+               InputStream in = null;
+               InputStream propertiesIn = null;
+               OutputStream out = null;
+               Properties properties = new Properties();
+               File jarFile = new File(
+                               "/home/mbaudier/dev/work/130129-Distribution/slf4j/slf4j-1.7.5/slf4j-api-1.7.5.jar");
+               File propertiesFile = new File(
+                               "/home/mbaudier/dev/git/git.argeo.org/distribution/bnd/org.slf4j/bnd.bnd");
+               try {
+                       in = new FileInputStream(jarFile);
+                       // propertiesIn = new FileInputStream(propertiesFile);
+                       out = new FileOutputStream(new File("test.jar"));
+                       // properties.load(propertiesIn);
+                       bndWrapper.wrapJar(properties, in, out);
+               } catch (Exception e) {
+                       throw new SlcException("Cannot test", e);
+               } finally {
+                       IOUtils.closeQuietly(in);
+                       IOUtils.closeQuietly(propertiesIn);
+                       IOUtils.closeQuietly(out);
+               }
+       }
+}
diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/DistributionWrapper.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/DistributionWrapper.java
new file mode 100644 (file)
index 0000000..094ee89
--- /dev/null
@@ -0,0 +1,119 @@
+package org.argeo.slc.repo.osgi;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Session;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.repo.OsgiFactory;
+import org.argeo.slc.repo.RepoUtils;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+
+/** Download a software distribution and generates the related OSGi bundles. */
+public class DistributionWrapper implements Runnable {
+       private final static Log log = LogFactory.getLog(DistributionWrapper.class);
+
+       private OsgiFactory osgiFactory;
+
+       private String version;
+       private String groupId;
+
+       private String uri;
+
+       private Map<String, BndWrapper> wrappers = new HashMap<String, BndWrapper>();
+
+       public void run() {
+
+               Session distSession = null;
+               Session javaSession = null;
+               ZipInputStream zin = null;
+               try {
+                       javaSession = osgiFactory.openJavaSession();
+                       distSession = osgiFactory.openDistSession();
+
+                       if (log.isDebugEnabled())
+                               log.debug("Wrapping " + uri);
+
+                       Node distNode = osgiFactory.getDist(distSession, uri);
+                       zin = new ZipInputStream(distNode.getNode(Node.JCR_CONTENT)
+                                       .getProperty(Property.JCR_DATA).getBinary().getStream());
+
+                       ZipEntry zentry = null;
+                       ByteArrayOutputStream out = null;
+                       ByteArrayInputStream in = null;
+                       while ((zentry = zin.getNextEntry()) != null) {
+                               try {
+                                       String name = zentry.getName();
+                                       // if (log.isDebugEnabled())
+                                       // log.debug("Scanning " + name);
+                                       if (wrappers.containsKey(name)) {
+
+                                               BndWrapper wrapper = (BndWrapper) wrappers.get(name);
+                                               if (wrapper.getVersion() == null)
+                                                       wrapper.setVersion(version);// FIXME stateful?
+
+                                               out = new ByteArrayOutputStream((int) zentry.getSize());
+                                               // we must copy since the stream is closed by BND
+                                               byte[] sourceJarBytes = IOUtils.toByteArray(zin);
+                                               in = new ByteArrayInputStream(sourceJarBytes);
+                                               Properties properties = new Properties();
+                                               wrapper.wrapJar(properties, in, out);
+
+                                               Artifact newArtifact = new DefaultArtifact(groupId,
+                                                               wrapper.getBsn(), "jar", wrapper.getVersion());
+                                               Node newJarNode = RepoUtils.copyBytesAsArtifact(
+                                                               javaSession.getRootNode(), newArtifact,
+                                                               out.toByteArray());
+                                               osgiFactory.indexNode(newJarNode);
+                                               if (log.isDebugEnabled())
+                                                       log.debug("Wrapped " + name + " to "
+                                                                       + newJarNode.getPath());
+                                       }
+                               } finally {
+                                       IOUtils.closeQuietly(out);
+                                       IOUtils.closeQuietly(in);
+                               }
+                       }
+               } catch (Exception e) {
+                       throw new SlcException("Cannot wrap distribution " + uri, e);
+               } finally {
+                       IOUtils.closeQuietly(zin);
+                       JcrUtils.logoutQuietly(distSession);
+                       JcrUtils.logoutQuietly(javaSession);
+               }
+       }
+
+       public void setVersion(String version) {
+               this.version = version;
+       }
+
+       public void setUri(String uri) {
+               this.uri = uri;
+       }
+
+       public void setWrappers(Map<String, BndWrapper> wrappers) {
+               this.wrappers = wrappers;
+       }
+
+       public void setGroupId(String groupId) {
+               this.groupId = groupId;
+       }
+
+       public void setOsgiFactory(OsgiFactory osgiFactory) {
+               this.osgiFactory = osgiFactory;
+       }
+
+}
diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/OsgiFactoryImpl.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/OsgiFactoryImpl.java
new file mode 100644 (file)
index 0000000..3381eb8
--- /dev/null
@@ -0,0 +1,134 @@
+package org.argeo.slc.repo.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcConstants;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.jcr.SlcNames;
+import org.argeo.slc.jcr.SlcTypes;
+import org.argeo.slc.repo.NodeIndexer;
+import org.argeo.slc.repo.OsgiFactory;
+
+public class OsgiFactoryImpl implements OsgiFactory {
+       private final static Log log = LogFactory.getLog(OsgiFactoryImpl.class);
+
+       private String workspace;
+       private Repository distRepository;
+       private Repository javaRepository;
+
+       private List<NodeIndexer> nodeIndexers = new ArrayList<NodeIndexer>();
+
+       public void init() {
+               if (workspace == null)
+                       throw new SlcException("A workspace must be specified");
+
+               Session javaSession = null;
+               Session distSession = null;
+               try {
+                       javaSession = JcrUtils.loginOrCreateWorkspace(javaRepository,
+                                       workspace);
+                       distSession = JcrUtils.loginOrCreateWorkspace(distRepository,
+                                       workspace);
+
+                       // Privileges
+                       JcrUtils.addPrivilege(javaSession, "/", SlcConstants.ROLE_SLC,
+                                       "jcr:all");
+                       JcrUtils.addPrivilege(distSession, "/", SlcConstants.ROLE_SLC,
+                                       "jcr:all");
+               } catch (RepositoryException e) {
+                       throw new SlcException("Cannot initialize OSGi Factory "
+                                       + workspace, e);
+               } finally {
+                       JcrUtils.logoutQuietly(javaSession);
+                       JcrUtils.logoutQuietly(distSession);
+               }
+       }
+
+       public void destroy() {
+
+       }
+
+       public Session openJavaSession() throws RepositoryException {
+               return javaRepository.login(workspace);
+       }
+
+       public Session openDistSession() throws RepositoryException {
+               return distRepository.login(workspace);
+       }
+
+       public void indexNode(Node node) {
+               for (NodeIndexer nodeIndexer : nodeIndexers) {
+                       nodeIndexer.index(node);
+               }
+       }
+
+       public Node getDist(Session distSession, String uri)
+                       throws RepositoryException {
+
+               String distPath = '/' + JcrUtils.urlAsPath(uri);
+
+               // TODO manage mirrors
+
+               if (!distSession.itemExists(distPath))
+                       loadUrlToPath(uri, distSession, distPath);
+               Node distNode = distSession.getNode(distPath);
+               return distNode;
+       }
+
+       protected void loadUrlToPath(String url, Session distSession, String path)
+                       throws RepositoryException {
+               if (log.isDebugEnabled())
+                       log.debug("Downloading " + url + "...");
+
+               InputStream in = null;
+               Node folderNode = JcrUtils.mkfolders(distSession,
+                               JcrUtils.parentPath(path));
+               try {
+                       URL u = new URL(url);
+                       in = u.openStream();
+                       Node fileNode = JcrUtils.copyStreamAsFile(folderNode,
+                                       JcrUtils.nodeNameFromPath(path), in);
+                       fileNode.addMixin(SlcTypes.SLC_KNOWN_ORIGIN);
+                       Node origin = fileNode.addNode(SlcNames.SLC_ORIGIN,
+                                       SlcTypes.SLC_PROXIED);
+                       JcrUtils.urlToAddressProperties(origin, url);
+                       distSession.save();
+
+               } catch (MalformedURLException e) {
+                       throw new SlcException("URL " + url + " not valid.", e);
+               } catch (IOException e) {
+                       throw new SlcException("Cannot load " + url + " to " + path, e);
+               }
+
+       }
+
+       public void setWorkspace(String workspace) {
+               this.workspace = workspace;
+       }
+
+       public void setDistRepository(Repository distRepository) {
+               this.distRepository = distRepository;
+       }
+
+       public void setJavaRepository(Repository javaRepository) {
+               this.javaRepository = javaRepository;
+       }
+
+       public void setNodeIndexers(List<NodeIndexer> nodeIndexers) {
+               this.nodeIndexers = nodeIndexers;
+       }
+
+}