1 package org
.argeo
.slc
.repo
;
3 import java
.io
.BufferedReader
;
4 import java
.io
.InputStream
;
5 import java
.io
.InputStreamReader
;
6 import java
.util
.ArrayList
;
7 import java
.util
.Collections
;
8 import java
.util
.Iterator
;
10 import java
.util
.Properties
;
11 import java
.util
.StringTokenizer
;
12 import java
.util
.jar
.JarEntry
;
13 import java
.util
.jar
.JarInputStream
;
14 import java
.util
.jar
.Manifest
;
16 import javax
.jcr
.Binary
;
17 import javax
.jcr
.Node
;
18 import javax
.jcr
.Property
;
19 import javax
.jcr
.RepositoryException
;
20 import javax
.jcr
.nodetype
.NodeType
;
21 import javax
.xml
.parsers
.DocumentBuilder
;
22 import javax
.xml
.parsers
.DocumentBuilderFactory
;
24 import org
.apache
.commons
.io
.FilenameUtils
;
25 import org
.apache
.commons
.io
.IOUtils
;
26 import org
.apache
.commons
.logging
.Log
;
27 import org
.apache
.commons
.logging
.LogFactory
;
28 import org
.argeo
.jcr
.JcrUtils
;
29 import org
.argeo
.slc
.CategorizedNameVersion
;
30 import org
.argeo
.slc
.DefaultNameVersion
;
31 import org
.argeo
.slc
.NameVersion
;
32 import org
.argeo
.slc
.SlcException
;
33 import org
.argeo
.slc
.aether
.AetherUtils
;
34 import org
.argeo
.slc
.build
.Distribution
;
35 import org
.argeo
.slc
.jcr
.SlcNames
;
36 import org
.argeo
.slc
.jcr
.SlcTypes
;
37 import org
.osgi
.framework
.Constants
;
38 import org
.sonatype
.aether
.artifact
.Artifact
;
39 import org
.sonatype
.aether
.util
.artifact
.DefaultArtifact
;
40 import org
.w3c
.dom
.Document
;
41 import org
.w3c
.dom
.Element
;
42 import org
.w3c
.dom
.NodeList
;
45 * Create or update JCR meta-data for an SLC Modular Distribution
47 * Currently, following types are managed: <list><li>* .jar: dependency
48 * artifacts with csv index</li> <li>.pom: artifact (binaries) that indexes a
49 * group, the .pom file contains a tag "dependencyManagement" that list all
50 * modules</li> </list>
52 public class ModularDistributionIndexer
implements NodeIndexer
, SlcNames
{
53 private final static Log log
= LogFactory
54 .getLog(ModularDistributionIndexer
.class);
56 // Constants for csv indexing
57 private final static String INDEX_FILE_NAME
= "modularDistribution.csv";
58 private String separator
= ",";
61 private final static List
<String
> BINARIES_ARTIFACTS_NAME
;
63 List
<String
> tmpList
= new ArrayList
<String
>();
64 tmpList
.add(RepoConstants
.BINARIES_ARTIFACT_ID
);
65 // tmpList.add(RepoConstants.SOURCES_ARTIFACT_ID);
66 // tmpList.add(RepoConstants.SDK_ARTIFACT_ID);
67 BINARIES_ARTIFACTS_NAME
= Collections
.unmodifiableList(tmpList
);
70 private Manifest manifest
;
72 // private Comparator<Artifact> artifactComparator = new
73 // ArtifactIdComparator();
75 public Boolean
support(String path
) {
76 if (FilenameUtils
.getExtension(path
).equals("jar"))
78 if (FilenameUtils
.getExtension(path
).equals("pom")
79 && BINARIES_ARTIFACTS_NAME
.contains(FilenameUtils
.getName(path
)
85 public void index(Node fileNode
) {
86 Binary fileBinary
= null;
89 String fileNodePath
= fileNode
.getPath();
90 if (!support(fileNodePath
))
93 if (!fileNode
.isNodeType(NodeType
.NT_FILE
))
96 Node contentNode
= fileNode
.getNode(Node
.JCR_CONTENT
);
97 fileBinary
= contentNode
.getProperty(Property
.JCR_DATA
).getBinary();
99 MyModularDistribution currDist
= null;
100 if (FilenameUtils
.getExtension(fileNode
.getPath()).equals("jar"))
101 currDist
= listModulesFromCsvIndex(fileNode
, fileBinary
);
102 else if (FilenameUtils
.getExtension(fileNode
.getPath()).equals(
104 currDist
= listModulesFromPomIndex(fileNode
, fileBinary
);
106 if (fileNode
.isNodeType(SlcTypes
.SLC_MODULAR_DISTRIBUTION
)
107 || currDist
== null || !currDist
.nameVersions().hasNext())
108 return; // already indexed or no modules found
110 fileNode
.addMixin(SlcTypes
.SLC_MODULAR_DISTRIBUTION
);
111 fileNode
.addMixin(SlcTypes
.SLC_CATEGORIZED_NAME_VERSION
);
112 if (currDist
.getCategory() != null)
113 fileNode
.setProperty(SLC_CATEGORY
, currDist
.getCategory());
114 fileNode
.setProperty(SLC_NAME
, currDist
.getName());
115 fileNode
.setProperty(SLC_VERSION
, currDist
.getVersion());
116 indexDistribution(currDist
, fileNode
);
119 if (log
.isTraceEnabled())
120 log
.trace("Indexed " + fileNode
+ " as modular distribution");
121 } catch (Exception e
) {
122 throw new SlcException("Cannot list dependencies from " + fileNode
,
127 private void indexDistribution(ArgeoOsgiDistribution osgiDist
, Node distNode
)
128 throws RepositoryException
{
129 distNode
.addMixin(SlcTypes
.SLC_MODULAR_DISTRIBUTION
);
130 distNode
.addMixin(SlcTypes
.SLC_CATEGORIZED_NAME_VERSION
);
131 distNode
.setProperty(SlcNames
.SLC_CATEGORY
, osgiDist
.getCategory());
132 distNode
.setProperty(SlcNames
.SLC_NAME
, osgiDist
.getName());
133 distNode
.setProperty(SlcNames
.SLC_VERSION
, osgiDist
.getVersion());
134 Node modules
= JcrUtils
.mkdirs(distNode
, SlcNames
.SLC_MODULES
,
135 NodeType
.NT_UNSTRUCTURED
);
137 for (Iterator
<?
extends NameVersion
> it
= osgiDist
.nameVersions(); it
139 addModule(modules
, it
.next());
143 private Node
addModule(Node modules
, NameVersion nameVersion
)
144 throws RepositoryException
{
145 CategorizedNameVersion cnv
= (CategorizedNameVersion
) nameVersion
;
146 Node moduleCoord
= null;
147 moduleCoord
= modules
.addNode(cnv
.getName(),
148 SlcTypes
.SLC_MODULE_COORDINATES
);
149 moduleCoord
.setProperty(SlcNames
.SLC_CATEGORY
, cnv
.getCategory());
150 moduleCoord
.setProperty(SlcNames
.SLC_NAME
, cnv
.getName());
151 moduleCoord
.setProperty(SlcNames
.SLC_VERSION
, cnv
.getVersion());
155 private MyModularDistribution
listModulesFromCsvIndex(Node fileNode
,
157 JarInputStream jarIn
= null;
158 BufferedReader reader
= null;
160 jarIn
= new JarInputStream(fileBinary
.getStream());
162 List
<CategorizedNameVersion
> modules
= new ArrayList
<CategorizedNameVersion
>();
165 manifest
= jarIn
.getManifest();
166 if (manifest
== null) {
167 log
.error(fileNode
+ " has no MANIFEST");
170 String category
= manifest
.getMainAttributes().getValue(
171 RepoConstants
.SLC_GROUP_ID
);
172 String name
= manifest
.getMainAttributes().getValue(
173 Constants
.BUNDLE_SYMBOLICNAME
);
174 String version
= manifest
.getMainAttributes().getValue(
175 Constants
.BUNDLE_VERSION
);
177 Artifact distribution
= new DefaultArtifact(category
, name
, "pom",
179 // Retrieve the index file
181 while ((indexEntry
= jarIn
.getNextJarEntry()) != null) {
182 String entryName
= indexEntry
.getName();
183 if (entryName
.equals(INDEX_FILE_NAME
)) {
188 } catch (SecurityException se
) {
189 log
.error("Invalid signature file digest "
190 + "for Manifest main attributes: " + entryName
191 + " while looking for an index in bundle " + name
);
194 if (indexEntry
== null)
195 return null; // Not a modular definition artifact
198 reader
= new BufferedReader(new InputStreamReader(jarIn
));
200 while ((line
= reader
.readLine()) != null) {
201 StringTokenizer st
= new StringTokenizer(line
, separator
);
202 st
.nextToken(); // moduleName
203 st
.nextToken(); // moduleVersion
204 String relativeUrl
= st
.nextToken();
205 Artifact currModule
= AetherUtils
.convertPathToArtifact(
207 modules
.add(new MyCategorizedNameVersion(currModule
208 .getGroupId(), currModule
.getArtifactId(), currModule
211 return new MyModularDistribution(distribution
, modules
);
212 } catch (Exception e
) {
213 throw new SlcException("Cannot list artifacts", e
);
215 IOUtils
.closeQuietly(jarIn
);
216 IOUtils
.closeQuietly(reader
);
220 private MyModularDistribution
listModulesFromPomIndex(Node fileNode
,
222 InputStream input
= null;
223 List
<CategorizedNameVersion
> modules
= new ArrayList
<CategorizedNameVersion
>();
225 input
= fileBinary
.getStream();
227 DocumentBuilder documentBuilder
= DocumentBuilderFactory
228 .newInstance().newDocumentBuilder();
229 Document doc
= documentBuilder
.parse(input
);
231 Properties props
= new Properties();
232 // props.setProperty("project.version",
233 // pomArtifact.getBaseVersion());
234 NodeList properties
= doc
.getElementsByTagName("properties");
235 if (properties
.getLength() > 0) {
236 NodeList propertiesElems
= properties
.item(0).getChildNodes();
237 for (int i
= 0; i
< propertiesElems
.getLength(); i
++) {
238 if (propertiesElems
.item(i
) instanceof Element
) {
239 Element property
= (Element
) propertiesElems
.item(i
);
240 props
.put(property
.getNodeName(),
241 property
.getTextContent());
246 // full coordinates are under <dependencyManagement><dependencies>
247 NodeList dependencies
= ((Element
) doc
.getElementsByTagName(
248 "dependencyManagement").item(0))
249 .getElementsByTagName("dependency");
250 for (int i
= 0; i
< dependencies
.getLength(); i
++) {
251 Element dependency
= (Element
) dependencies
.item(i
);
252 String groupId
= dependency
.getElementsByTagName("groupId")
253 .item(0).getTextContent().trim();
254 String artifactId
= dependency
255 .getElementsByTagName("artifactId").item(0)
256 .getTextContent().trim();
257 String version
= dependency
.getElementsByTagName("version")
258 .item(0).getTextContent().trim();
259 modules
.add(new MyCategorizedNameVersion(groupId
, artifactId
,
263 String groupId
= doc
.getElementsByTagName("groupId").item(0)
264 .getTextContent().trim();
265 String artifactId
= doc
.getElementsByTagName("artifactId").item(0)
266 .getTextContent().trim();
267 String version
= doc
.getElementsByTagName("version").item(0)
268 .getTextContent().trim();
270 Artifact currDist
= new DefaultArtifact(groupId
, artifactId
, "pom",
273 return new MyModularDistribution(currDist
, modules
);
274 } catch (Exception e
) {
275 throw new SlcException("Cannot process pom " + fileNode
, e
);
277 IOUtils
.closeQuietly(input
);
281 /** The created modular distribution */
282 private static class MyCategorizedNameVersion
extends DefaultNameVersion
283 implements CategorizedNameVersion
{
284 private final String category
;
286 public MyCategorizedNameVersion(String category
, String name
,
288 super(name
, version
);
289 this.category
= category
;
292 public String
getCategory() {
298 * A consistent and versioned OSGi distribution, which can be built and
301 private class MyModularDistribution
extends ArtifactDistribution
implements
302 ArgeoOsgiDistribution
{
304 private List
<CategorizedNameVersion
> modules
;
306 public MyModularDistribution(Artifact artifact
,
307 List
<CategorizedNameVersion
> modules
) {
309 this.modules
= modules
;
312 public Iterator
<CategorizedNameVersion
> nameVersions() {
313 return modules
.iterator();
316 // Modular distribution interface methods. Not yet used.
317 public Distribution
getModuleDistribution(String moduleName
,
318 String moduleVersion
) {
322 public Object
getModulesDescriptor(String descriptorType
) {
327 /** Separator used to parse the tabular file, default is "," */
328 public void setSeparator(String modulesUrlSeparator
) {
329 this.separator
= modulesUrlSeparator
;