]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ArchiveWrapper.java
SLC Unit
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / osgi / ArchiveWrapper.java
index 438552e4b91189b192c624f06fe06145bef6126f..29fa8f14d8dba8790cb631241307d924c3eaeb3e 100644 (file)
@@ -2,6 +2,7 @@ package org.argeo.slc.repo.osgi;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -9,23 +10,29 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.jar.JarInputStream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
 
 import javax.jcr.Node;
 import javax.jcr.Property;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.apache.commons.io.FilenameUtils;
 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.CategorizedNameVersion;
+import org.argeo.slc.DefaultNameVersion;
 import org.argeo.slc.ModuleSet;
 import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
 import org.argeo.slc.aether.ArtifactIdComparator;
 import org.argeo.slc.build.Distribution;
+import org.argeo.slc.build.License;
 import org.argeo.slc.repo.OsgiFactory;
 import org.argeo.slc.repo.RepoUtils;
 import org.sonatype.aether.artifact.Artifact;
@@ -33,6 +40,8 @@ import org.sonatype.aether.util.artifact.DefaultArtifact;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.PathMatcher;
 
+import aQute.lib.osgi.Jar;
+
 /**
  * Download a software distribution and generates the related OSGi bundles from
  * the jars, or import them directly if they are already OSGi bundles and don't
@@ -43,12 +52,15 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
 
        private OsgiFactory osgiFactory;
        private String version;
+       private License license;
 
        private String uri;
 
-       // jars to wrap as OSGi bundles
+       /** Jars to wrap as OSGi bundles */
        private Map<String, BndWrapper> wrappers = new HashMap<String, BndWrapper>();
 
+       private SourcesProvider sourcesProvider;
+
        // pattern of OSGi bundles to import
        private PathMatcher pathMatcher = new AntPathMatcher();
        private Map<String, String> includes = new HashMap<String, String>();
@@ -57,11 +69,13 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
        private Boolean mavenGroupIndexes = false;
 
        public void init() {
-               if (version != null)
-                       for (BndWrapper wrapper : wrappers.values()) {
-                               if (wrapper.getVersion() == null)
-                                       wrapper.setVersion(version);
-                       }
+               for (BndWrapper wrapper : wrappers.values()) {
+                       wrapper.setFactory(this);
+                       if (version != null && wrapper.getVersion() == null)
+                               wrapper.setVersion(version);
+                       if (license != null && wrapper.getLicense() == null)
+                               wrapper.setLicense(license);
+               }
        }
 
        public void destroy() {
@@ -73,7 +87,65 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
        }
 
        public Iterator<? extends NameVersion> nameVersions() {
-               return wrappers.values().iterator();
+               if (wrappers.size() > 0)
+                       return wrappers.values().iterator();
+               else
+                       return osgiNameVersions();
+       }
+
+       @SuppressWarnings("resource")
+       protected Iterator<? extends NameVersion> osgiNameVersions() {
+               List<CategorizedNameVersion> nvs = new ArrayList<CategorizedNameVersion>();
+
+               Session distSession = null;
+               ZipInputStream zin = null;
+               try {
+                       distSession = osgiFactory.openDistSession();
+
+                       Node distNode = osgiFactory.getDist(distSession, uri);
+                       zin = new ZipInputStream(distNode.getNode(Node.JCR_CONTENT)
+                                       .getProperty(Property.JCR_DATA).getBinary().getStream());
+
+                       ZipEntry zentry = null;
+                       entries: while ((zentry = zin.getNextEntry()) != null) {
+                               String name = zentry.getName();
+                               if (log.isTraceEnabled())
+                                       log.trace("Zip entry " + name);
+                               for (String exclude : excludes)
+                                       if (pathMatcher.match(exclude, name))
+                                               continue entries;
+
+                               for (String include : includes.keySet()) {
+                                       if (pathMatcher.match(include, name)) {
+                                               String groupId = includes.get(include);
+                                               JarInputStream jis = new JarInputStream(zin);
+                                               if (jis.getManifest() == null) {
+                                                       log.warn("No MANIFEST in entry " + name
+                                                                       + ", skipping...");
+                                                       continue entries;
+                                               }
+                                               NameVersion nv = RepoUtils.readNameVersion(jis
+                                                               .getManifest());
+                                               if (nv != null) {
+                                                       if (nv.getName().endsWith(".source"))
+                                                               continue entries;
+                                                       CategorizedNameVersion cnv = new OsgiCategorizedNV(
+                                                                       groupId, nv.getName(), nv.getVersion(),
+                                                                       this);
+                                                       nvs.add(cnv);
+                                                       // no need to process further includes
+                                                       continue entries;
+                                               }
+                                       }
+                               }
+                       }
+                       return nvs.iterator();
+               } catch (Exception e) {
+                       throw new SlcException("Cannot wrap distribution " + uri, e);
+               } finally {
+                       IOUtils.closeQuietly(zin);
+                       JcrUtils.logoutQuietly(distSession);
+               }
        }
 
        public void run() {
@@ -93,6 +165,7 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
 
                        if (log.isDebugEnabled())
                                log.debug("Wrapping " + uri);
+                       boolean nothingWasDone = true;
 
                        Node distNode = osgiFactory.getDist(distSession, uri);
                        zin = new ZipInputStream(distNode.getNode(Node.JCR_CONTENT)
@@ -101,14 +174,69 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
                        ZipEntry zentry = null;
                        entries: while ((zentry = zin.getNextEntry()) != null) {
                                String name = zentry.getName();
+
+                               // sources autodetect
+                               String baseName = FilenameUtils.getBaseName(name);
+                               if (baseName.endsWith("-sources")) {
+                                       String bundle = baseName.substring(0, baseName.length()
+                                                       - "-sources".length());
+                                       // log.debug(name + "," + baseName + ", " + bundle);
+                                       String bundlePath = FilenameUtils.getPath(name) + bundle
+                                                       + ".jar";
+                                       if (wrappers.containsKey(bundlePath)) {
+                                               BndWrapper wrapper = wrappers.get(bundlePath);
+                                               NameVersion bundleNv = new DefaultNameVersion(
+                                                               wrapper.getName(), wrapper.getVersion());
+                                               byte[] pdeSource = RepoUtils.packageAsPdeSource(zin,
+                                                               bundleNv);
+                                               Artifact sourcesArtifact = new DefaultArtifact(
+                                                               wrapper.getCategory(), wrapper.getName()
+                                                                               + ".source", "jar",
+                                                               wrapper.getVersion());
+                                               Node pdeSourceNode = RepoUtils.copyBytesAsArtifact(
+                                                               javaSession.getRootNode(), sourcesArtifact,
+                                                               pdeSource);
+                                               osgiFactory.indexNode(pdeSourceNode);
+                                               pdeSourceNode.getSession().save();
+                                               if (log.isDebugEnabled())
+                                                       log.debug("Added sources " + sourcesArtifact
+                                                                       + " for bundle " + wrapper.getArtifact()
+                                                                       + "from " + name + " in binary archive.");
+                                       }
+
+                               }
+                               // else if (baseName.endsWith(".source")) {
+                               // }
+
+                               // binaries
                                if (wrappers.containsKey(name)) {
                                        BndWrapper wrapper = (BndWrapper) wrappers.get(name);
                                        // we must copy since the stream is closed by BND
-                                       byte[] sourceJarBytes = IOUtils.toByteArray(zin);
+                                       byte[] origJarBytes = IOUtils.toByteArray(zin);
                                        Artifact artifact = wrapZipEntry(javaSession, zentry,
-                                                       sourceJarBytes, wrapper);
+                                                       origJarBytes, wrapper);
+                                       nothingWasDone = false;
                                        addArtifactToIndex(binaries, wrapper.getGroupId(), artifact);
                                } else {
+                                       for (String wrapperKey : wrappers.keySet())
+                                               if (pathMatcher.match(wrapperKey, name)) {
+                                                       // first matched is taken
+                                                       BndWrapper wrapper = (BndWrapper) wrappers
+                                                                       .get(wrapperKey);
+                                                       // we must copy since the stream is closed by BND
+                                                       byte[] origJarBytes = IOUtils.toByteArray(zin);
+                                                       Artifact artifact = wrapZipEntry(javaSession,
+                                                                       zentry, origJarBytes, wrapper);
+                                                       nothingWasDone = false;
+                                                       addArtifactToIndex(binaries, wrapper.getGroupId(),
+                                                                       artifact);
+                                                       continue entries;
+                                               } else {
+                                                       if (log.isTraceEnabled())
+                                                               log.trace(name + " not matched by "
+                                                                               + wrapperKey);
+                                               }
+
                                        for (String exclude : excludes)
                                                if (pathMatcher.match(exclude, name))
                                                        continue entries;
@@ -116,13 +244,20 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
                                        for (String include : includes.keySet()) {
                                                if (pathMatcher.match(include, name)) {
                                                        String groupId = includes.get(include);
-                                                       byte[] sourceJarBytes = IOUtils.toByteArray(zin);
+                                                       byte[] origJarBytes = IOUtils.toByteArray(zin);
                                                        Artifact artifact = importZipEntry(javaSession,
-                                                                       zentry, sourceJarBytes, groupId);
+                                                                       zentry, origJarBytes, groupId);
+                                                       if (artifact == null) {
+                                                               log.warn("Skipped non identified " + zentry);
+                                                               continue entries;
+                                                       }
+                                                       nothingWasDone = false;
                                                        if (artifact.getArtifactId().endsWith(".source"))
                                                                addArtifactToIndex(sources, groupId, artifact);
                                                        else
                                                                addArtifactToIndex(binaries, groupId, artifact);
+                                                       // no need to process this entry further
+                                                       continue entries;
                                                }
                                        }
                                }
@@ -138,6 +273,10 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
                                }
                        }
 
+                       if (nothingWasDone)
+                               throw new SlcException("Nothing was done");
+
+                       // FIXME Fail if not all wrappers matched
                } catch (Exception e) {
                        throw new SlcException("Cannot wrap distribution " + uri, e);
                } finally {
@@ -148,14 +287,14 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
        }
 
        protected Artifact wrapZipEntry(Session javaSession, ZipEntry zentry,
-                       byte[] sourceJarBytes, BndWrapper wrapper)
-                       throws RepositoryException {
+                       byte[] origJarBytes, BndWrapper wrapper) throws RepositoryException {
                ByteArrayOutputStream out = null;
                ByteArrayInputStream in = null;
                Node newJarNode;
+               Jar jar = null;
                try {
                        out = new ByteArrayOutputStream((int) zentry.getSize());
-                       in = new ByteArrayInputStream(sourceJarBytes);
+                       in = new ByteArrayInputStream(origJarBytes);
                        wrapper.wrapJar(in, out);
 
                        Artifact artifact = wrapper.getArtifact();
@@ -166,29 +305,83 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
                        if (log.isDebugEnabled())
                                log.debug("Wrapped jar " + zentry.getName() + " to "
                                                + newJarNode.getPath());
+
+                       if (sourcesProvider != null)
+                               addSource(javaSession, artifact, out.toByteArray());
+
                        return artifact;
                } finally {
                        IOUtils.closeQuietly(in);
                        IOUtils.closeQuietly(out);
+                       if (jar != null)
+                               jar.close();
+               }
+       }
+
+       protected void addSource(Session javaSession, Artifact artifact,
+                       byte[] binaryJarBytes) {
+               InputStream in = null;
+               ByteArrayOutputStream out = null;
+               Jar jar = null;
+               try {
+                       in = new ByteArrayInputStream(binaryJarBytes);
+                       jar = new Jar(null, in);
+                       List<String> packages = jar.getPackages();
+
+                       out = new ByteArrayOutputStream();
+                       sourcesProvider.writeSources(packages, new ZipOutputStream(out));
+
+                       IOUtils.closeQuietly(in);
+                       in = new ByteArrayInputStream(out.toByteArray());
+                       byte[] sourcesJar = RepoUtils.packageAsPdeSource(
+                                       in,
+                                       new DefaultNameVersion(artifact.getArtifactId(), artifact
+                                                       .getVersion()));
+                       Artifact sourcesArtifact = new DefaultArtifact(
+                                       artifact.getGroupId(),
+                                       artifact.getArtifactId() + ".source", "jar",
+                                       artifact.getVersion());
+                       Node sourcesJarNode = RepoUtils.copyBytesAsArtifact(
+                                       javaSession.getRootNode(), sourcesArtifact, sourcesJar);
+                       sourcesJarNode.getSession().save();
+
+                       if (log.isDebugEnabled())
+                               log.debug("Added sources " + sourcesArtifact + " for bundle "
+                                               + artifact + "from source provider " + sourcesProvider);
+               } catch (Exception e) {
+                       throw new SlcException("Cannot get sources for " + artifact, e);
+               } finally {
+                       IOUtils.closeQuietly(in);
+                       IOUtils.closeQuietly(out);
+                       if (jar != null)
+                               jar.close();
                }
        }
 
        protected Artifact importZipEntry(Session javaSession, ZipEntry zentry,
-                       byte[] sourceJarBytes, String groupId) throws RepositoryException {
+                       byte[] binaryJarBytes, String groupId) throws RepositoryException {
                ByteArrayInputStream in = null;
                Node newJarNode;
                try {
-                       in = new ByteArrayInputStream(sourceJarBytes);
+                       in = new ByteArrayInputStream(binaryJarBytes);
                        NameVersion nameVersion = RepoUtils.readNameVersion(in);
+                       if (nameVersion == null) {
+                               log.warn("Cannot identify " + zentry.getName());
+                               return null;
+                       }
                        Artifact artifact = new DefaultArtifact(groupId,
                                        nameVersion.getName(), "jar", nameVersion.getVersion());
                        newJarNode = RepoUtils.copyBytesAsArtifact(
-                                       javaSession.getRootNode(), artifact, sourceJarBytes);
+                                       javaSession.getRootNode(), artifact, binaryJarBytes);
                        osgiFactory.indexNode(newJarNode);
                        newJarNode.getSession().save();
                        if (log.isDebugEnabled())
                                log.debug("Imported OSGi bundle " + zentry.getName() + " to "
                                                + newJarNode.getPath());
+
+                       if (sourcesProvider != null)
+                               addSource(javaSession, artifact, binaryJarBytes);
+
                        return artifact;
                } finally {
                        IOUtils.closeQuietly(in);
@@ -219,6 +412,10 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
                this.version = version;
        }
 
+       public void setLicense(License license) {
+               this.license = license;
+       }
+
        public void setPathMatcher(PathMatcher pathMatcher) {
                this.pathMatcher = pathMatcher;
        }
@@ -235,4 +432,8 @@ public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
                this.mavenGroupIndexes = mavenGroupIndexes;
        }
 
+       public void setSourcesProvider(SourcesProvider sourcesProvider) {
+               this.sourcesProvider = sourcesProvider;
+       }
+
 }