1 package org
.argeo
.slc
.repo
;
3 import java
.io
.BufferedReader
;
4 import java
.io
.InputStreamReader
;
5 import java
.util
.ArrayList
;
6 import java
.util
.Iterator
;
8 import java
.util
.StringTokenizer
;
9 import java
.util
.jar
.JarEntry
;
10 import java
.util
.jar
.JarInputStream
;
11 import java
.util
.jar
.Manifest
;
13 import javax
.jcr
.Binary
;
14 import javax
.jcr
.Node
;
15 import javax
.jcr
.Property
;
16 import javax
.jcr
.RepositoryException
;
17 import javax
.jcr
.nodetype
.NodeType
;
19 import org
.apache
.commons
.io
.FilenameUtils
;
20 import org
.apache
.commons
.io
.IOUtils
;
21 import org
.apache
.commons
.logging
.Log
;
22 import org
.apache
.commons
.logging
.LogFactory
;
23 import org
.argeo
.jcr
.JcrUtils
;
24 import org
.argeo
.slc
.CategorizedNameVersion
;
25 import org
.argeo
.slc
.DefaultNameVersion
;
26 import org
.argeo
.slc
.NameVersion
;
27 import org
.argeo
.slc
.SlcException
;
28 import org
.argeo
.slc
.SlcNames
;
29 import org
.argeo
.slc
.SlcTypes
;
30 import org
.argeo
.slc
.build
.Distribution
;
31 import org
.argeo
.slc
.repo
.maven
.AetherUtils
;
32 import org
.eclipse
.aether
.artifact
.Artifact
;
33 import org
.eclipse
.aether
.artifact
.DefaultArtifact
;
34 import org
.osgi
.framework
.Constants
;
37 * Create or update JCR meta-data for an SLC Modular Distribution
39 * Currently, following types are managed: <list>
40 * <li>* .jar: dependency artifacts with csv index</li>
41 * <li>@Deprecated : .pom: artifact (binaries) that indexes a group, the .pom
42 * file contains a tag "dependencyManagement" that list all modules</li> </list>
44 public class ModularDistributionIndexer
implements NodeIndexer
, SlcNames
{
45 private final static Log log
= LogFactory
.getLog(ModularDistributionIndexer
.class);
47 // Constants for csv indexing
48 private final static String INDEX_FILE_NAME
= "modularDistribution.csv";
49 private String separator
= ",";
51 private Manifest manifest
;
53 public Boolean
support(String path
) {
54 if (FilenameUtils
.getExtension(path
).equals("jar"))
59 public void index(Node fileNode
) {
60 Binary fileBinary
= null;
62 String fileNodePath
= fileNode
.getPath();
63 if (!support(fileNodePath
))
66 if (!fileNode
.isNodeType(NodeType
.NT_FILE
))
69 Node contentNode
= fileNode
.getNode(Node
.JCR_CONTENT
);
70 fileBinary
= contentNode
.getProperty(Property
.JCR_DATA
).getBinary();
72 MyModularDistribution currDist
= null;
73 if (FilenameUtils
.getExtension(fileNode
.getPath()).equals("jar"))
74 currDist
= listModulesFromCsvIndex(fileNode
, fileBinary
);
76 if (fileNode
.isNodeType(SlcTypes
.SLC_MODULAR_DISTRIBUTION
) || currDist
== null
77 || !currDist
.nameVersions().hasNext())
78 return; // already indexed or no modules found
80 fileNode
.addMixin(SlcTypes
.SLC_MODULAR_DISTRIBUTION
);
81 fileNode
.addMixin(SlcTypes
.SLC_CATEGORIZED_NAME_VERSION
);
82 if (currDist
.getCategory() != null)
83 fileNode
.setProperty(SLC_CATEGORY
, currDist
.getCategory());
84 fileNode
.setProperty(SLC_NAME
, currDist
.getName());
85 fileNode
.setProperty(SLC_VERSION
, currDist
.getVersion());
86 indexDistribution(currDist
, fileNode
);
89 if (log
.isTraceEnabled())
90 log
.trace("Indexed " + fileNode
+ " as modular distribution");
91 } catch (Exception e
) {
92 throw new SlcException("Cannot list dependencies from " + fileNode
, e
);
94 JcrUtils
.closeQuietly(fileBinary
);
98 private void indexDistribution(ArgeoOsgiDistribution osgiDist
, Node distNode
) throws RepositoryException
{
99 distNode
.addMixin(SlcTypes
.SLC_MODULAR_DISTRIBUTION
);
100 distNode
.addMixin(SlcTypes
.SLC_CATEGORIZED_NAME_VERSION
);
101 distNode
.setProperty(SlcNames
.SLC_CATEGORY
, osgiDist
.getCategory());
102 distNode
.setProperty(SlcNames
.SLC_NAME
, osgiDist
.getName());
103 distNode
.setProperty(SlcNames
.SLC_VERSION
, osgiDist
.getVersion());
104 if (distNode
.hasNode(SLC_MODULES
))
105 distNode
.getNode(SLC_MODULES
).remove();
106 Node modules
= distNode
.addNode(SLC_MODULES
, NodeType
.NT_UNSTRUCTURED
);
108 for (Iterator
<?
extends NameVersion
> it
= osgiDist
.nameVersions(); it
.hasNext();)
109 addModule(modules
, it
.next());
113 private Node
addModule(Node modules
, NameVersion nameVersion
) throws RepositoryException
{
114 CategorizedNameVersion cnv
= (CategorizedNameVersion
) nameVersion
;
115 Node moduleCoord
= null;
116 moduleCoord
= modules
.addNode(cnv
.getName(), SlcTypes
.SLC_MODULE_COORDINATES
);
117 moduleCoord
.setProperty(SlcNames
.SLC_CATEGORY
, cnv
.getCategory());
118 moduleCoord
.setProperty(SlcNames
.SLC_NAME
, cnv
.getName());
119 moduleCoord
.setProperty(SlcNames
.SLC_VERSION
, cnv
.getVersion());
123 private MyModularDistribution
listModulesFromCsvIndex(Node fileNode
, Binary fileBinary
) {
124 JarInputStream jarIn
= null;
125 BufferedReader reader
= null;
127 jarIn
= new JarInputStream(fileBinary
.getStream());
129 List
<CategorizedNameVersion
> modules
= new ArrayList
<CategorizedNameVersion
>();
132 manifest
= jarIn
.getManifest();
133 if (manifest
== null) {
134 log
.error(fileNode
+ " has no MANIFEST");
137 String category
= manifest
.getMainAttributes().getValue(RepoConstants
.SLC_CATEGORY_ID
);
138 String name
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_SYMBOLICNAME
);
139 String version
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_VERSION
);
141 Artifact distribution
= new DefaultArtifact(category
, name
, "jar", version
);
142 // Retrieve the index file
144 while ((indexEntry
= jarIn
.getNextJarEntry()) != null) {
145 String entryName
= indexEntry
.getName();
146 if (entryName
.equals(INDEX_FILE_NAME
)) {
151 } catch (SecurityException se
) {
152 log
.error("Invalid signature file digest " + "for Manifest main attributes: " + entryName
153 + " while looking for an index in bundle " + name
);
156 if (indexEntry
== null)
157 return null; // Not a modular definition
159 if (category
== null) {
160 log
.warn("Modular definition found but no " + RepoConstants
.SLC_CATEGORY_ID
+ " in " + fileNode
);
164 reader
= new BufferedReader(new InputStreamReader(jarIn
));
166 while ((line
= reader
.readLine()) != null) {
167 StringTokenizer st
= new StringTokenizer(line
, separator
);
168 st
.nextToken(); // moduleName
169 st
.nextToken(); // moduleVersion
170 String relativeUrl
= st
.nextToken();
171 Artifact currModule
= AetherUtils
.convertPathToArtifact(relativeUrl
, null);
172 modules
.add(new MyCategorizedNameVersion(currModule
.getGroupId(), currModule
.getArtifactId(),
173 currModule
.getVersion()));
175 return new MyModularDistribution(distribution
, modules
);
176 } catch (Exception e
) {
177 throw new SlcException("Cannot list artifacts", e
);
179 IOUtils
.closeQuietly(jarIn
);
180 IOUtils
.closeQuietly(reader
);
184 /** The created modular distribution */
185 private static class MyCategorizedNameVersion
extends DefaultNameVersion
implements CategorizedNameVersion
{
186 private final String category
;
188 public MyCategorizedNameVersion(String category
, String name
, String version
) {
189 super(name
, version
);
190 this.category
= category
;
193 public String
getCategory() {
199 * A consistent and versioned OSGi distribution, which can be built and tested.
201 private class MyModularDistribution
extends ArtifactDistribution
implements ArgeoOsgiDistribution
{
203 private List
<CategorizedNameVersion
> modules
;
205 public MyModularDistribution(Artifact artifact
, List
<CategorizedNameVersion
> modules
) {
207 this.modules
= modules
;
210 public Iterator
<CategorizedNameVersion
> nameVersions() {
211 return modules
.iterator();
214 // Modular distribution interface methods. Not yet used.
215 public Distribution
getModuleDistribution(String moduleName
, String moduleVersion
) {
219 public Object
getModulesDescriptor(String descriptorType
) {
224 /** Separator used to parse the tabular file, default is "," */
225 public void setSeparator(String modulesUrlSeparator
) {
226 this.separator
= modulesUrlSeparator
;