From: Bruno Sinou Date: Thu, 12 Jun 2014 20:58:49 +0000 (+0000) Subject: First working version of modular distribution creation while running the ProcessDistr... X-Git-Tag: argeo-slc-2.1.7~171 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=1a0340b557d4cd38e763e4922a3ee4e5dcc8f6d3;p=gpl%2Fargeo-slc.git First working version of modular distribution creation while running the ProcessDistribution bean. git-svn-id: https://svn.argeo.org/slc/trunk@7055 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionFactory.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionFactory.java new file mode 100644 index 000000000..db22db66c --- /dev/null +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionFactory.java @@ -0,0 +1,550 @@ +package org.argeo.slc.repo; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.CategorizedNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; +import org.osgi.framework.Constants; +import org.sonatype.aether.artifact.Artifact; +import org.sonatype.aether.util.artifact.DefaultArtifact; + +/** + * Creates a jar bundle from an ArgeoOsgiDistribution. This jar is then + * persisted and indexed in a java repository. + * + * It does the following
  • Creates a Manifest
  • Creates files + * indexes (csv, feature.xml ...)
  • Populate the corresponding jar
  • + * Save it in the repository
  • Index the node and creates corresponding + * sha1 and md5 files
  • + * + */ +public class ModularDistributionFactory implements Runnable { + + private Session javaSession; + private ArgeoOsgiDistribution osgiDistribution; + private String modularDistributionSeparator = ","; + private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH; + private String artifactType = "jar"; + + // Constants + private final static String CSV_FILE_NAME = "modularDistribution.csv"; + private final static String FEATURE_FILE_NAME = "feature.xml"; + public static int BUFFER_SIZE = 10240; + + /** Convenience constructor with minimal configuration */ + public ModularDistributionFactory(Session javaSession, + ArgeoOsgiDistribution osgiDistribution) { + this.javaSession = javaSession; + this.osgiDistribution = osgiDistribution; + } + + @Override + public void run() { + internalCreateDistribution(); + } + + private void internalCreateDistribution() { + byte[] distFile = null; + try { + if (artifactType == "jar") + distFile = generateJarFile(); + else if (artifactType == "pom") + distFile = generatePomFile(); + else + throw new SlcException( + "Unimplemented distribution azrtiofact type " + + artifactType + " for " + + osgiDistribution.toString()); + + // Save in java repository + Artifact osgiArtifact = new DefaultArtifact( + osgiDistribution.getCategory(), osgiDistribution.getName(), + artifactType, osgiDistribution.getVersion()); + + Node distNode = RepoUtils.copyBytesAsArtifact( + javaSession.getNode(artifactBasePath), osgiArtifact, + distFile); + + // index + indexDistribution(distNode); + + // Really ? + javaSession.save(); + } catch (RepositoryException e) { + throw new SlcException( + "JCR error while persisting modular distribution in JCR " + + osgiDistribution.toString(), e); + } + } + + private byte[] generateJarFile() { + ByteArrayOutputStream byteOut = null; + JarOutputStream jarOut = null; + try { + byteOut = new ByteArrayOutputStream(); + jarOut = new JarOutputStream(byteOut, createManifest()); + // Create various indexes + addToJar(createCsvDescriptor(), CSV_FILE_NAME, jarOut); + return byteOut.toByteArray(); + } catch (IOException e) { + throw new SlcException( + "IO error while generating modular distribution " + + osgiDistribution.toString(), e); + } finally { + IOUtils.closeQuietly(byteOut); + IOUtils.closeQuietly(jarOut); + } + } + + private void indexDistribution(Node distNode) throws RepositoryException { + distNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION); + distNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION); + distNode.setProperty(SlcNames.SLC_CATEGORY, + osgiDistribution.getCategory()); + distNode.setProperty(SlcNames.SLC_NAME, osgiDistribution.getName()); + distNode.setProperty(SlcNames.SLC_VERSION, + osgiDistribution.getVersion()); + + Node modules = JcrUtils.mkdirs(distNode, SlcNames.SLC_MODULES, + NodeType.NT_UNSTRUCTURED); + + for (Iterator it = osgiDistribution + .nameVersions(); it.hasNext();) + addModule(modules, it.next()); + } + + private Manifest createManifest() { + Manifest manifest = new Manifest(); + + // TODO make this configurable + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, + "1.0"); + addManifestAttribute(manifest, + Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, "JavaSE-1.6"); + addManifestAttribute(manifest, Constants.BUNDLE_VENDOR, "Argeo"); + addManifestAttribute(manifest, Constants.BUNDLE_MANIFESTVERSION, "2"); + addManifestAttribute(manifest, "Bundle-License", + "http://www.apache.org/licenses/LICENSE-2.0.txt"); + + // TODO define a user friendly name + addManifestAttribute(manifest, Constants.BUNDLE_NAME, + osgiDistribution.getName()); + + // Categorized name version + addManifestAttribute(manifest, RepoConstants.SLC_GROUP_ID, + osgiDistribution.getCategory()); + addManifestAttribute(manifest, Constants.BUNDLE_SYMBOLICNAME, + osgiDistribution.getName()); + addManifestAttribute(manifest, Constants.BUNDLE_VERSION, + osgiDistribution.getVersion()); + + return manifest; + } + + private void addManifestAttribute(Manifest manifest, String name, + String value) { + manifest.getMainAttributes().put(new Attributes.Name(name), value); + } + + private byte[] createCsvDescriptor() { + Writer writer = null; + try { + // FIXME remove use of tmp file. + File tmpFile = File.createTempFile("modularDistribution", "csv"); + tmpFile.deleteOnExit(); + writer = new FileWriter(tmpFile); + // Populate the file + for (Iterator it = osgiDistribution + .nameVersions(); it.hasNext();) + writer.write(getCsvLine(it.next())); + writer.flush(); + return FileUtils.readFileToByteArray(tmpFile); + } catch (Exception e) { + throw new SlcException( + "unable to create csv distribution file for " + + osgiDistribution.toString(), e); + } finally { + IOUtils.closeQuietly(writer); + } + } + + private byte[] createFeatureDescriptor() { + // Directly retrieved from Argeo maven plugin + // Does not work due to the lack of org.codehaus.plexus/plexus-archiver + // third party dependency + + throw new SlcException("Unimplemented method"); + + // // protected void writeFeatureDescriptor() throws + // MojoExecutionException { + // File featureDesc = File.createTempFile("feature", "xml"); + // featureDesc.deleteOnExit(); + // + // Writer writer = null; + // try { + // writer = new FileWriter(featureDesc); + // PrettyPrintXMLWriter xmlWriter = new PrettyPrintXMLWriter(writer); + // xmlWriter.startElement("feature"); + // xmlWriter.addAttribute("id", project.getArtifactId()); + // xmlWriter.addAttribute("label", project.getName()); + // + // // Version + // String projectVersion = project.getVersion(); + // int indexSnapshot = projectVersion.indexOf("-SNAPSHOT"); + // if (indexSnapshot > -1) + // projectVersion = projectVersion.substring(0, indexSnapshot); + // projectVersion = projectVersion + ".qualifier"; + // + // // project. + // xmlWriter.addAttribute("version", projectVersion); + // + // Organization organization = project.getOrganization(); + // if (organization != null && organization.getName() != null) + // xmlWriter.addAttribute("provider-name", organization.getName()); + // + // if (project.getDescription() != null || project.getUrl() != null) { + // xmlWriter.startElement("description"); + // if (project.getUrl() != null) + // xmlWriter.addAttribute("url", project.getUrl()); + // if (project.getDescription() != null) + // xmlWriter.writeText(project.getDescription()); + // xmlWriter.endElement();// description + // } + // + // if (feature != null && feature.getCopyright() != null + // || (organization != null && organization.getUrl() != null)) { + // xmlWriter.startElement("copyright"); + // if (organization != null && organization.getUrl() != null) + // xmlWriter.addAttribute("url", organization.getUrl()); + // if (feature.getCopyright() != null) + // xmlWriter.writeText(feature.getCopyright()); + // xmlWriter.endElement();// copyright + // } + // + // if (feature != null && feature.getUpdateSite() != null) { + // xmlWriter.startElement("url"); + // xmlWriter.startElement("update"); + // xmlWriter.addAttribute("url", feature.getUpdateSite()); + // xmlWriter.endElement();// update + // xmlWriter.endElement();// url + // } + // + // List licenses = project.getLicenses(); + // if (licenses.size() > 0) { + // // take the first one + // License license = (License) licenses.get(0); + // xmlWriter.startElement("license"); + // + // if (license.getUrl() != null) + // xmlWriter.addAttribute("url", license.getUrl()); + // if (license.getComments() != null) + // xmlWriter.writeText(license.getComments()); + // else if (license.getName() != null) + // xmlWriter.writeText(license.getName()); + // xmlWriter.endElement();// license + // } + // + // // deploymentRepository.pathOf(null); + // if (jarDirectory == null) { + // Set dependencies = mavenDependencyManager + // .getTransitiveProjectDependencies(project, remoteRepos, + // local); + // // // protected void writeFeatureDescriptor() throws + // MojoExecutionException { + // File featureDesc = File.createTempFile("feature", "xml"); + // featureDesc.deleteOnExit(); + // + // Writer writer = null; + // try { + // writer = new FileWriter(featureDesc); + // PrettyPrintXMLWriter xmlWriter = new PrettyPrintXMLWriter(writer); + // xmlWriter.startElement("feature"); + // xmlWriter.addAttribute("id", project.getArtifactId()); + // xmlWriter.addAttribute("label", project.getName()); + // + // // Version + // String projectVersion = project.getVersion(); + // int indexSnapshot = projectVersion.indexOf("-SNAPSHOT"); + // if (indexSnapshot > -1) + // projectVersion = projectVersion.substring(0, indexSnapshot); + // projectVersion = projectVersion + ".qualifier"; + // + // // project. + // xmlWriter.addAttribute("version", projectVersion); + // + // Organization organization = project.getOrganization(); + // if (organization != null && organization.getName() != null) + // xmlWriter.addAttribute("provider-name", organization.getName()); + // + // if (project.getDescription() != null || project.getUrl() != null) { + // xmlWriter.startElement("description"); + // if (project.getUrl() != null) + // xmlWriter.addAttribute("url", project.getUrl()); + // if (project.getDescription() != null) + // xmlWriter.writeText(project.getDescription()); + // xmlWriter.endElement();// description + // } + // + // if (feature != null && feature.getCopyright() != null + // || (organization != null && organization.getUrl() != null)) { + // xmlWriter.startElement("copyright"); + // if (organization != null && organization.getUrl() != null) + // xmlWriter.addAttribute("url", organization.getUrl()); + // if (feature.getCopyright() != null) + // xmlWriter.writeText(feature.getCopyright()); + // xmlWriter.endElement();// copyright + // } + // + // if (feature != null && feature.getUpdateSite() != null) { + // xmlWriter.startElement("url"); + // xmlWriter.startElement("update"); + // xmlWriter.addAttribute("url", feature.getUpdateSite()); + // xmlWriter.endElement();// update + // xmlWriter.endElement();// url + // } + // + // List licenses = project.getLicenses(); + // if (licenses.size() > 0) { + // // take the first one + // License license = (License) licenses.get(0); + // xmlWriter.startElement("license"); + // + // if (license.getUrl() != null) + // xmlWriter.addAttribute("url", license.getUrl()); + // if (license.getComments() != null) + // xmlWriter.writeText(license.getComments()); + // else if (license.getName() != null) + // xmlWriter.writeText(license.getName()); + // xmlWriter.endElement();// license + // } + // + // // deploymentRepository.pathOf(null); + // if (jarDirectory == null) { + // Set dependencies = mavenDependencyManager + // .getTransitiveProjectDependencies(project, remoteRepos, + // local); + // for (Iterator it = dependencies.iterator(); it.hasNext();) { + // Artifact artifact = (Artifact) it.next(); + // writeFeaturePlugin(xmlWriter, artifact.getFile()); + // } + // } else { + // // TODO: filter jars + // File[] jars = jarDirectory.listFiles(); + // if (jars == null) + // throw new MojoExecutionException("No jar found in " + // + jarDirectory); + // for (int i = 0; i < jars.length; i++) { + // writeFeaturePlugin(xmlWriter, jars[i]); + // } + // } + // + // xmlWriter.endElement();// feature + // + // if (getLog().isDebugEnabled()) + // getLog().debug("Wrote Eclipse feature descriptor."); + // } catch (Exception e) { + // throw new MojoExecutionException("Cannot write feature descriptor", + // e); + // } finally { + // IOUtil.close(writer); + // }for (Iterator it = dependencies.iterator(); it.hasNext();) { + // Artifact artifact = (Artifact) it.next(); + // writeFeaturePlugin(xmlWriter, artifact.getFile()); + // } + // } else { + // // TODO: filter jars + // File[] jars = jarDirectory.listFiles(); + // if (jars == null) + // throw new MojoExecutionException("No jar found in " + // + jarDirectory); + // for (int i = 0; i < jars.length; i++) { + // writeFeaturePlugin(xmlWriter, jars[i]); + // } + // } + // + // xmlWriter.endElement();// feature + // + // if (getLog().isDebugEnabled()) + // getLog().debug("Wrote Eclipse feature descriptor."); + // } catch (Exception e) { + // throw new MojoExecutionException("Cannot write feature descriptor", + // e); + // } finally { + // IOUtil.close(writer); + // } + } + + /** Create an Aether like distribution artifact */ + private byte[] generatePomFile() { + StringBuilder b = new StringBuilder(); + // XML header + b.append("\n"); + b.append("\n"); + b.append("4.0.0"); + + // Artifact + b.append("").append(osgiDistribution.getCategory()) + .append("\n"); + b.append("").append(osgiDistribution.getName()) + .append("\n"); + b.append("").append(osgiDistribution.getVersion()) + .append("\n"); + b.append("pom\n"); + // p.append("").append("Bundle Name").append("\n"); + // p.append("").append("Bundle Description").append("\n"); + + // Dependencies + b.append("\n"); + for (Iterator it = osgiDistribution + .nameVersions(); it.hasNext();) { + NameVersion nameVersion = it.next(); + if (!(nameVersion instanceof CategorizedNameVersion)) + throw new SlcException("Unsupported type " + + nameVersion.getClass()); + CategorizedNameVersion nv = (CategorizedNameVersion) nameVersion; + b.append(getDependencySnippet(nv, false)); + } + b.append("\n"); + + // Dependency management + b.append("\n"); + b.append("\n"); + + for (Iterator it = osgiDistribution + .nameVersions(); it.hasNext();) + b.append(getDependencySnippet((CategorizedNameVersion) it.next(), + true)); + b.append("\n"); + b.append("\n"); + + b.append("\n"); + return b.toString().getBytes(); + } + + private String getDependencySnippet(CategorizedNameVersion cnv, + boolean includeVersion) { // , String type, String scope + StringBuilder b = new StringBuilder(); + b.append("\n"); + b.append("\t").append(cnv.getCategory()) + .append("\n"); + b.append("\t").append(cnv.getName()) + .append("\n"); + if (includeVersion) + b.append("\t").append(cnv.getVersion()) + .append("\n"); + // if (type!= null) + // p.append("\t").append(type).append("\n"); + // if (type!= null) + // p.append("\t").append(scope).append("\n"); + b.append("\n"); + return b.toString(); + } + + // Helpers + private Node addModule(Node modules, NameVersion nameVersion) + throws RepositoryException { + CategorizedNameVersion cnv = (CategorizedNameVersion) nameVersion; + Node moduleCoord = null; + // TODO solve the same name issue + // if (modules.hasNode(cnv.getName())) + // moduleCoord = modules.getNode(cnv.getName()); + // else { + moduleCoord = modules.addNode(cnv.getName(), + SlcTypes.SLC_MODULE_COORDINATES); + moduleCoord.setProperty(SlcNames.SLC_CATEGORY, cnv.getCategory()); + moduleCoord.setProperty(SlcNames.SLC_NAME, cnv.getName()); + moduleCoord.setProperty(SlcNames.SLC_VERSION, cnv.getVersion()); + // } + return moduleCoord; + } + + private void addToJar(byte[] content, String name, JarOutputStream target) + throws IOException { + ByteArrayInputStream in = null; + try { + target.putNextEntry(new JarEntry(name)); + in = new ByteArrayInputStream(content); + byte[] buffer = new byte[1024]; + while (true) { + int count = in.read(buffer); + if (count == -1) + break; + target.write(buffer, 0, count); + } + target.closeEntry(); + } finally { + IOUtils.closeQuietly(in); + } + } + + private String getCsvLine(NameVersion nameVersion) + throws RepositoryException { + if (!(nameVersion instanceof CategorizedNameVersion)) + throw new SlcException("Unsupported type " + nameVersion.getClass()); + CategorizedNameVersion cnv = (CategorizedNameVersion) nameVersion; + StringBuilder builder = new StringBuilder(); + + builder.append(cnv.getName()); + builder.append(modularDistributionSeparator); + builder.append(nameVersion.getVersion()); + builder.append(modularDistributionSeparator); + builder.append(cnv.getCategory().replace('.', '/')); + // MavenConventionsUtils.groupPath("", cnv.getCategory()); + builder.append('/'); + builder.append(cnv.getName()); + builder.append('/'); + builder.append(cnv.getVersion()); + builder.append('/'); + builder.append(cnv.getName()); + builder.append('-'); + builder.append(cnv.getVersion()); + builder.append('.'); + // TODO make this dynamic + builder.append("jar"); + builder.append("\n"); + + return builder.toString(); + } + + public void setJavaSession(Session javaSession) { + this.javaSession = javaSession; + } + + public void setOsgiDistribution(ArgeoOsgiDistribution osgiDistribution) { + this.osgiDistribution = osgiDistribution; + } + + public void setModularDistributionSeparator( + String modularDistributionSeparator) { + this.modularDistributionSeparator = modularDistributionSeparator; + } + + public void setArtifactBasePath(String artifactBasePath) { + this.artifactBasePath = artifactBasePath; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } +} \ No newline at end of file diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionIndexer.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionIndexer.java index 59c6b31f3..3070b9b75 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionIndexer.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionIndexer.java @@ -5,12 +5,10 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.Properties; -import java.util.Set; import java.util.StringTokenizer; -import java.util.TreeSet; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.jar.Manifest; @@ -18,6 +16,7 @@ import java.util.jar.Manifest; import javax.jcr.Binary; import javax.jcr.Node; import javax.jcr.Property; +import javax.jcr.RepositoryException; import javax.jcr.nodetype.NodeType; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -29,9 +28,10 @@ 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.NameVersion; import org.argeo.slc.SlcException; import org.argeo.slc.aether.AetherUtils; -import org.argeo.slc.aether.ArtifactIdComparator; +import org.argeo.slc.build.Distribution; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; import org.osgi.framework.Constants; @@ -68,19 +68,13 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { } private Manifest manifest; - // private String symbolicName; - // private String version; - // private List artifacts; - private Comparator artifactComparator = new ArtifactIdComparator(); - - // private Set artifacts = new - // TreeSet(artifactComparator); + // private Comparator artifactComparator = new + // ArtifactIdComparator(); public Boolean support(String path) { if (FilenameUtils.getExtension(path).equals("jar")) return true; - if (FilenameUtils.getExtension(path).equals("pom") && BINARIES_ARTIFACTS_NAME.contains(FilenameUtils.getName(path) .split("-")[0])) @@ -89,7 +83,6 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { } public void index(Node fileNode) { - // JarInputStream jarIn = null; Binary fileBinary = null; try { @@ -100,57 +93,27 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { if (!fileNode.isNodeType(NodeType.NT_FILE)) return; - // Session jcrSession = fileNode.getSession(); Node contentNode = fileNode.getNode(Node.JCR_CONTENT); fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary(); - Set artifacts = new TreeSet(artifactComparator); - - MyCategorizedNameVersion currCatNV = null; - + MyModularDistribution currDist = null; if (FilenameUtils.getExtension(fileNode.getPath()).equals("jar")) - currCatNV = listModulesFromCsvIndex(artifacts, fileNode, - fileBinary); + currDist = listModulesFromCsvIndex(fileNode, fileBinary); else if (FilenameUtils.getExtension(fileNode.getPath()).equals( "pom")) - currCatNV = listModulesFromPomIndex(artifacts, fileNode, - fileBinary); + currDist = listModulesFromPomIndex(fileNode, fileBinary); - if (artifacts.isEmpty()) - return; // no modules found + if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION) + || currDist == null || !currDist.nameVersions().hasNext()) + return; // already indexed or no modules found else { - Node modules; - if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION)) { - modules = fileNode.getNode(SlcNames.SLC_MODULES); - } else { - fileNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION); - fileNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION); - if (currCatNV.getCategory() != null) - fileNode.setProperty(SLC_CATEGORY, - currCatNV.getCategory()); - fileNode.setProperty(SLC_NAME, currCatNV.getName()); - fileNode.setProperty(SLC_VERSION, currCatNV.getVersion()); - modules = JcrUtils.mkdirs(fileNode, SlcNames.SLC_MODULES, - NodeType.NT_UNSTRUCTURED); - } - - for (Artifact artifact : artifacts) { - // TODO clean this once an overwrite policy has been - // decided. - if (!modules.hasNode(artifact.getArtifactId())) { - Node moduleCoord = modules.addNode( - artifact.getArtifactId(), - SlcTypes.SLC_MODULE_COORDINATES); - moduleCoord.setProperty(SlcNames.SLC_NAME, - artifact.getArtifactId()); - moduleCoord.setProperty(SlcNames.SLC_VERSION, - artifact.getVersion()); - String groupId = artifact.getGroupId(); - if (groupId != null && !"".equals(groupId.trim())) - moduleCoord.setProperty(SlcNames.SLC_CATEGORY, - artifact.getGroupId()); - } - } + fileNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION); + fileNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION); + if (currDist.getCategory() != null) + fileNode.setProperty(SLC_CATEGORY, currDist.getCategory()); + fileNode.setProperty(SLC_NAME, currDist.getName()); + fileNode.setProperty(SLC_VERSION, currDist.getVersion()); + indexDistribution(currDist, fileNode); } if (log.isTraceEnabled()) @@ -161,26 +124,58 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { } } - protected MyCategorizedNameVersion listModulesFromCsvIndex( - Set artifacts, Node fileNode, Binary fileBinary) { + private void indexDistribution(ArgeoOsgiDistribution osgiDist, Node distNode) + throws RepositoryException { + distNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION); + distNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION); + distNode.setProperty(SlcNames.SLC_CATEGORY, osgiDist.getCategory()); + distNode.setProperty(SlcNames.SLC_NAME, osgiDist.getName()); + distNode.setProperty(SlcNames.SLC_VERSION, osgiDist.getVersion()); + Node modules = JcrUtils.mkdirs(distNode, SlcNames.SLC_MODULES, + NodeType.NT_UNSTRUCTURED); + + for (Iterator it = osgiDist.nameVersions(); it + .hasNext();) + addModule(modules, it.next()); + } + + // Helpers + private Node addModule(Node modules, NameVersion nameVersion) + throws RepositoryException { + CategorizedNameVersion cnv = (CategorizedNameVersion) nameVersion; + Node moduleCoord = null; + moduleCoord = modules.addNode(cnv.getName(), + SlcTypes.SLC_MODULE_COORDINATES); + moduleCoord.setProperty(SlcNames.SLC_CATEGORY, cnv.getCategory()); + moduleCoord.setProperty(SlcNames.SLC_NAME, cnv.getName()); + moduleCoord.setProperty(SlcNames.SLC_VERSION, cnv.getVersion()); + return moduleCoord; + } + + private MyModularDistribution listModulesFromCsvIndex(Node fileNode, + Binary fileBinary) { JarInputStream jarIn = null; BufferedReader reader = null; try { jarIn = new JarInputStream(fileBinary.getStream()); + List modules = new ArrayList(); + // meta data manifest = jarIn.getManifest(); if (manifest == null) { log.error(fileNode + " has no MANIFEST"); return null; } - String symbolicName = manifest.getMainAttributes().getValue( + String category = manifest.getMainAttributes().getValue( + RepoConstants.SLC_GROUP_ID); + String name = manifest.getMainAttributes().getValue( Constants.BUNDLE_SYMBOLICNAME); String version = manifest.getMainAttributes().getValue( Constants.BUNDLE_VERSION); - String category = manifest.getMainAttributes().getValue( - "SLC-GroupId"); + Artifact distribution = new DefaultArtifact(category, name, "pom", + version); // Retrieve the index file JarEntry indexEntry; while ((indexEntry = jarIn.getNextJarEntry()) != null) { @@ -193,8 +188,7 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { } catch (SecurityException se) { log.error("Invalid signature file digest " + "for Manifest main attributes: " + entryName - + " while looking for an index in bundle " - + symbolicName); + + " while looking for an index in bundle " + name); } } if (indexEntry == null) @@ -208,13 +202,13 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { st.nextToken(); // moduleName st.nextToken(); // moduleVersion String relativeUrl = st.nextToken(); - artifacts.add(AetherUtils.convertPathToArtifact(relativeUrl, - null)); - // if (log.isTraceEnabled()) - // log.trace("Processed dependency: " + line); + Artifact currModule = AetherUtils.convertPathToArtifact( + relativeUrl, null); + modules.add(new MyCategorizedNameVersion(currModule + .getGroupId(), currModule.getArtifactId(), currModule + .getVersion())); } - - return new MyCategorizedNameVersion(category, symbolicName, version); + return new MyModularDistribution(distribution, modules); } catch (Exception e) { throw new SlcException("Cannot list artifacts", e); } finally { @@ -223,16 +217,16 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { } } - protected MyCategorizedNameVersion listModulesFromPomIndex( - Set artifacts, Node fileNode, Binary fileBinary) { + private MyModularDistribution listModulesFromPomIndex(Node fileNode, + Binary fileBinary) { InputStream input = null; + List modules = new ArrayList(); try { input = fileBinary.getStream(); DocumentBuilder documentBuilder = DocumentBuilderFactory .newInstance().newDocumentBuilder(); Document doc = documentBuilder.parse(input); - // properties Properties props = new Properties(); // props.setProperty("project.version", @@ -262,29 +256,8 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { .getTextContent().trim(); String version = dependency.getElementsByTagName("version") .item(0).getTextContent().trim(); - // if (version.startsWith("${")) { - // String versionKey = version.substring(0, - // version.length() - 1).substring(2); - // if (!props.containsKey(versionKey)) - // throw new SlcException("Cannot interpret version " - // + version); - // version = props.getProperty(versionKey); - // } - // NodeList scopes = dependency.getElementsByTagName("scope"); - // if (scopes.getLength() > 0 - // && scopes.item(0).getTextContent().equals("import")) { - // // recurse - // gatherPomDependencies(aetherTemplate, artifacts, - // new DefaultArtifact(groupId, artifactId, "pom", - // version)); - // } else { - // TODO: deal with scope? - // TODO: deal with type - String type = "jar"; - Artifact artifact = new DefaultArtifact(groupId, artifactId, - type, version); - artifacts.add(artifact); - // } + modules.add(new MyCategorizedNameVersion(groupId, artifactId, + version)); } String groupId = doc.getElementsByTagName("groupId").item(0) @@ -294,8 +267,10 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { String version = doc.getElementsByTagName("version").item(0) .getTextContent().trim(); - return new MyCategorizedNameVersion(groupId, artifactId, version); + Artifact currDist = new DefaultArtifact(groupId, artifactId, "pom", + version); + return new MyModularDistribution(currDist, modules); } catch (Exception e) { throw new SlcException("Cannot process pom " + fileNode, e); } finally { @@ -303,11 +278,6 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { } } - /** Separator used to parse the tabular file, default is "," */ - public void setSeparator(String modulesUrlSeparator) { - this.separator = modulesUrlSeparator; - } - /** The created modular distribution */ private static class MyCategorizedNameVersion extends DefaultNameVersion implements CategorizedNameVersion { @@ -323,4 +293,40 @@ public class ModularDistributionIndexer implements NodeIndexer, SlcNames { return category; } } + + /** + * A consistent and versioned OSGi distribution, which can be built and + * tested. + */ + private class MyModularDistribution extends ArtifactDistribution implements + ArgeoOsgiDistribution { + + private List modules; + + public MyModularDistribution(Artifact artifact, + List modules) { + super(artifact); + this.modules = modules; + } + + public Iterator nameVersions() { + return modules.iterator(); + } + + // Modular distribution interface methods. Not yet used. + public Distribution getModuleDistribution(String moduleName, + String moduleVersion) { + return null; + } + + public Object getModulesDescriptor(String descriptorType) { + return null; + } + } + + /** Separator used to parse the tabular file, default is "," */ + public void setSeparator(String modulesUrlSeparator) { + this.separator = modulesUrlSeparator; + } + } \ No newline at end of file diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoConstants.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoConstants.java index 7a81e7102..4358e9865 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoConstants.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoConstants.java @@ -31,4 +31,7 @@ public interface RepoConstants { public final static String BINARIES_ARTIFACT_ID = "binaries"; public final static String SOURCES_ARTIFACT_ID = "sources"; public final static String SDK_ARTIFACT_ID = "sdk"; + + // TODO might exists somewhere else + public final static String SLC_GROUP_ID = "SLC-GroupId"; } diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoUtils.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoUtils.java index b0e65bce5..1aee15835 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoUtils.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoUtils.java @@ -483,7 +483,7 @@ public class RepoUtils implements ArgeoNames, SlcNames { /** * Write group indexes: 'binaries' lists all bundles and their versions, - * 'sources' list theire sources, and 'sdk' aggregates both. + * 'sources' list their sources, and 'sdk' aggregates both. */ public static void writeGroupIndexes(Session session, String artifactBasePath, String groupId, String version, diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ArgeoOsgiDistributionImpl.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ArgeoOsgiDistributionImpl.java index 4591598df..08746b5e2 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ArgeoOsgiDistributionImpl.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ArgeoOsgiDistributionImpl.java @@ -69,17 +69,6 @@ public class ArgeoOsgiDistributionImpl extends ArtifactDistribution implements } - public Distribution getModuleDistribution(String moduleName, - String moduleVersion) { - // NameVersion searched = new DefaultNameVersion(moduleName, - // moduleVersion); - // for (Distribution ad : modules) { - // if (ad.equals(searched)) - // return ad; - // } - return null; - } - public Iterator nameVersions() { List nameVersions = new ArrayList(); for (Object module : modules) { @@ -109,13 +98,25 @@ public class ArgeoOsgiDistributionImpl extends ArtifactDistribution implements } } + // Modular distribution interface methods. Not yet used. + public Distribution getModuleDistribution(String moduleName, + String moduleVersion) { + // NameVersion searched = new DefaultNameVersion(moduleName, + // moduleVersion); + // for (Distribution ad : modules) { + // if (ad.equals(searched)) + // return ad; + // } + return null; + } + public Object getModulesDescriptor(String descriptorType) { // TODO Auto-generated method stub return null; } + /* DEPENDENCY INJECTION */ public void setModules(List modules) { this.modules = modules; } - } diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ProcessDistribution.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ProcessDistribution.java index bca8356c9..d852fb623 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ProcessDistribution.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/ProcessDistribution.java @@ -12,6 +12,7 @@ import org.argeo.slc.CategorizedNameVersion; import org.argeo.slc.NameVersion; import org.argeo.slc.SlcException; import org.argeo.slc.repo.ArgeoOsgiDistribution; +import org.argeo.slc.repo.ModularDistributionFactory; import org.argeo.slc.repo.OsgiFactory; import org.argeo.slc.repo.maven.MavenConventionsUtils; import org.sonatype.aether.artifact.Artifact; @@ -33,8 +34,15 @@ public class ProcessDistribution implements Runnable { .nameVersions(); it.hasNext();) processNameVersion(javaSession, it.next()); - // TODO generate distribution indexes (pom.xml, P2, OBR) + ModularDistributionFactory mdf = new ModularDistributionFactory( + javaSession, osgiDistribution); + mdf.run(); + // javaSession.save(); + // osgiFactory.indexNode(node); + // Node artifact = createDistributionArtifact(javaSession, + // osgiDistribution); + } catch (RepositoryException e) { throw new SlcException("Cannot process distribution " + osgiDistribution, e); @@ -65,9 +73,9 @@ public class ProcessDistribution implements Runnable { if (log.isDebugEnabled()) log.debug("Already available : " + nv); } - } + /* DEPENDENCY INJECTION */ public void setOsgiDistribution(ArgeoOsgiDistribution osgiDistribution) { this.osgiDistribution = osgiDistribution; } @@ -75,5 +83,4 @@ public class ProcessDistribution implements Runnable { public void setOsgiFactory(OsgiFactory osgiFactory) { this.osgiFactory = osgiFactory; } - -} +} \ No newline at end of file