X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.slc.repo%2Fsrc%2Forg%2Fargeo%2Fslc%2Frepo%2FModularDistributionIndexer.java;fp=org.argeo.slc.repo%2Fsrc%2Forg%2Fargeo%2Fslc%2Frepo%2FModularDistributionIndexer.java;h=7d854a1c5d23c3e7b0dbb744109b49c6d528c154;hb=825d60c5348dbe3f5be25b0bccf7bdebfe694219;hp=0000000000000000000000000000000000000000;hpb=5e991fff5cba01858dcc5747a27e637325bc5c8e;p=gpl%2Fargeo-jcr.git diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java new file mode 100644 index 0000000..7d854a1 --- /dev/null +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java @@ -0,0 +1,213 @@ +package org.argeo.slc.repo; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +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 org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.argeo.api.cms.CmsLog; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.CategoryNameVersion; +import org.argeo.slc.DefaultCategoryNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.SlcNames; +import org.argeo.slc.SlcTypes; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.repo.maven.AetherUtils; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.osgi.framework.Constants; + +/** + * Create or update JCR meta-data for an SLC Modular Distribution + * + * Currently, following types are managed: + *
  • * .jar: dependency artifacts with csv index
  • + *
  • @Deprecated : .pom: artifact (binaries) that indexes a group, the .pom + * file contains a tag "dependencyManagement" that list all modules
  • + */ +public class ModularDistributionIndexer implements NodeIndexer, SlcNames { + private final static CmsLog log = CmsLog.getLog(ModularDistributionIndexer.class); + + // Constants for csv indexing + private final static String INDEX_FILE_NAME = "modularDistribution.csv"; + private String separator = ","; + + private Manifest manifest; + + public Boolean support(String path) { + if (FilenameUtils.getExtension(path).equals("jar")) + return true; + return false; + } + + public void index(Node fileNode) { + Binary fileBinary = null; + try { + String fileNodePath = fileNode.getPath(); + if (!support(fileNodePath)) + return; + + if (!fileNode.isNodeType(NodeType.NT_FILE)) + return; + + Node contentNode = fileNode.getNode(Node.JCR_CONTENT); + fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary(); + + MyModularDistribution currDist = null; + if (FilenameUtils.getExtension(fileNode.getPath()).equals("jar")) + currDist = listModulesFromCsvIndex(fileNode, fileBinary); + + if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION) || currDist == null + || !currDist.nameVersions().hasNext()) + return; // already indexed or no modules found + else { + 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()) + log.trace("Indexed " + fileNode + " as modular distribution"); + } catch (Exception e) { + throw new SlcException("Cannot list dependencies from " + fileNode, e); + } finally { + JcrUtils.closeQuietly(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()); + if (distNode.hasNode(SLC_MODULES)) + distNode.getNode(SLC_MODULES).remove(); + Node modules = distNode.addNode(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 { + CategoryNameVersion cnv = (CategoryNameVersion) 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 category = manifest.getMainAttributes().getValue(RepoConstants.SLC_CATEGORY_ID); + String name = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); + String version = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION); + + Artifact distribution = new DefaultArtifact(category, name, "jar", version); + // Retrieve the index file + JarEntry indexEntry; + while ((indexEntry = jarIn.getNextJarEntry()) != null) { + String entryName = indexEntry.getName(); + if (entryName.equals(INDEX_FILE_NAME)) { + break; + } + try { + jarIn.closeEntry(); + } catch (SecurityException se) { + log.error("Invalid signature file digest " + "for Manifest main attributes: " + entryName + + " while looking for an index in bundle " + name); + } + } + if (indexEntry == null) + return null; // Not a modular definition + + if (category == null) { + log.warn("Modular definition found but no " + RepoConstants.SLC_CATEGORY_ID + " in " + fileNode); + } + + // Process the index + reader = new BufferedReader(new InputStreamReader(jarIn)); + String line = null; + while ((line = reader.readLine()) != null) { + StringTokenizer st = new StringTokenizer(line, separator); + st.nextToken(); // moduleName + st.nextToken(); // moduleVersion + String relativeUrl = st.nextToken(); + Artifact currModule = AetherUtils.convertPathToArtifact(relativeUrl, null); + modules.add(new DefaultCategoryNameVersion(currModule.getGroupId(), currModule.getArtifactId(), + currModule.getVersion())); + } + return new MyModularDistribution(distribution, modules); + } catch (Exception e) { + throw new SlcException("Cannot list artifacts", e); + } finally { + IOUtils.closeQuietly(jarIn); + IOUtils.closeQuietly(reader); + } + } + + /** + * 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