<?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
public void index(Node fileNode) {
Artifact artifact = null;
try {
+ if(!support(fileNode.getPath()))
+ return;
+
if (!fileNode.isNodeType(NodeType.NT_FILE))
return;
ByteArrayInputStream bi = null;
Binary manifestBinary = null;
try {
+ if(!support(fileNode.getPath()))
+ return;
+
if (!fileNode.isNodeType(NodeType.NT_FILE))
return;
--- /dev/null
+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;
+}
--- /dev/null
+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);
+ }
+ }
+}
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+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;
+ }
+
+}