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
.Comparator
;
10 import java
.util
.Properties
;
12 import java
.util
.StringTokenizer
;
13 import java
.util
.TreeSet
;
14 import java
.util
.jar
.JarEntry
;
15 import java
.util
.jar
.JarInputStream
;
16 import java
.util
.jar
.Manifest
;
18 import javax
.jcr
.Binary
;
19 import javax
.jcr
.Node
;
20 import javax
.jcr
.Property
;
21 import javax
.jcr
.nodetype
.NodeType
;
22 import javax
.xml
.parsers
.DocumentBuilder
;
23 import javax
.xml
.parsers
.DocumentBuilderFactory
;
25 import org
.apache
.commons
.io
.FilenameUtils
;
26 import org
.apache
.commons
.io
.IOUtils
;
27 import org
.apache
.commons
.logging
.Log
;
28 import org
.apache
.commons
.logging
.LogFactory
;
29 import org
.argeo
.jcr
.JcrUtils
;
30 import org
.argeo
.slc
.SlcException
;
31 import org
.argeo
.slc
.aether
.AetherUtils
;
32 import org
.argeo
.slc
.aether
.ArtifactIdComparator
;
33 import org
.argeo
.slc
.jcr
.SlcNames
;
34 import org
.argeo
.slc
.jcr
.SlcTypes
;
35 import org
.sonatype
.aether
.artifact
.Artifact
;
36 import org
.sonatype
.aether
.util
.artifact
.DefaultArtifact
;
37 import org
.w3c
.dom
.Document
;
38 import org
.w3c
.dom
.Element
;
39 import org
.w3c
.dom
.NodeList
;
42 * Create or update JCR meta-data for modularDistribution bundles: <list><li>
43 * .jar: dependency artifacts with csv index</li> <li>.pom: group index artifact
44 * (binaries, sources) with tag dependency management</li> </list>
46 public class DistributionBundleIndexer
implements NodeIndexer
{
47 private final static Log log
= LogFactory
48 .getLog(DistributionBundleIndexer
.class);
50 private final static String INDEX_FILE_NAME
= "modularDistribution.csv";
51 private final static List
<String
> BINARIES_ARTIFACTS_NAME
;
53 List
<String
> tmpList
= new ArrayList
<String
>();
54 tmpList
.add(RepoConstants
.BINARIES_ARTIFACT_ID
);
55 //tmpList.add(RepoConstants.SOURCES_ARTIFACT_ID);
56 //tmpList.add(RepoConstants.SDK_ARTIFACT_ID);
57 BINARIES_ARTIFACTS_NAME
= Collections
.unmodifiableList(tmpList
);
60 private Manifest manifest
;
61 // private String symbolicName;
62 // private String version;
64 // private List<Artifact> artifacts;
65 private String separator
= ",";
67 private Comparator
<Artifact
> artifactComparator
= new ArtifactIdComparator();
69 // private Set<Artifact> artifacts = new
70 // TreeSet<Artifact>(artifactComparator);
72 public Boolean
support(String path
) {
73 if (FilenameUtils
.getExtension(path
).equals("jar"))
76 if (FilenameUtils
.getExtension(path
).equals("pom")
77 && BINARIES_ARTIFACTS_NAME
.contains(FilenameUtils
.getName(path
)
83 public void index(Node fileNode
) {
84 // JarInputStream jarIn = null;
85 Binary fileBinary
= null;
88 String fileNodePath
= fileNode
.getPath();
89 if (!support(fileNodePath
))
92 if (!fileNode
.isNodeType(NodeType
.NT_FILE
))
95 // Session jcrSession = fileNode.getSession();
96 Node contentNode
= fileNode
.getNode(Node
.JCR_CONTENT
);
97 fileBinary
= contentNode
.getProperty(Property
.JCR_DATA
).getBinary();
99 Set
<Artifact
> artifacts
= new TreeSet
<Artifact
>(artifactComparator
);
101 if (FilenameUtils
.getExtension(fileNode
.getPath()).equals("jar"))
102 listModulesFromCsvIndex(artifacts
, fileNode
, fileBinary
);
103 else if (FilenameUtils
.getExtension(fileNode
.getPath()).equals(
105 listModulesFromPomIndex(artifacts
, fileNode
, fileBinary
);
107 if (artifacts
.isEmpty())
108 return; // no modules found
111 if (fileNode
.isNodeType(SlcTypes
.SLC_MODULAR_DISTRIBUTION
)) {
112 modules
= fileNode
.getNode(SlcNames
.SLC_MODULES
);
114 fileNode
.addMixin(SlcTypes
.SLC_MODULAR_DISTRIBUTION
);
115 modules
= JcrUtils
.mkdirs(fileNode
, SlcNames
.SLC_MODULES
,
116 NodeType
.NT_UNSTRUCTURED
);
119 for (Artifact artifact
: artifacts
) {
120 // TODO clean this once an overwrite policy has been
122 if (!modules
.hasNode(artifact
.getArtifactId())) {
123 Node moduleCoord
= modules
.addNode(
124 artifact
.getArtifactId(),
125 SlcTypes
.SLC_MODULE_COORDINATES
);
126 moduleCoord
.setProperty(SlcNames
.SLC_NAME
,
127 artifact
.getArtifactId());
128 moduleCoord
.setProperty(SlcNames
.SLC_VERSION
,
129 artifact
.getVersion());
130 String groupId
= artifact
.getGroupId();
131 if (groupId
!= null && !"".equals(groupId
.trim()))
132 moduleCoord
.setProperty(SlcNames
.SLC_CATEGORY
,
133 artifact
.getGroupId());
140 // won't work if distribution artifact is not listed
141 // for (int i = 0; i < artifacts.size(); i++) {
142 // OsgiArtifact osgiArtifact = artifacts.get(i);
143 // if (osgiArtifact.getSymbolicName().equals(symbolicName)
144 // && osgiArtifact.getVersion().equals(version)) {
145 // String relativeUrl = osgiArtifact.getRelativeUrl();
146 // if (url.endsWith(relativeUrl)) {
147 // baseUrl = url.substring(0, url.length()
148 // - osgiArtifact.getRelativeUrl().length());
153 } catch (Exception e
) {
154 throw new SlcException("Cannot list dependencies from " + fileNode
,
159 protected void listModulesFromCsvIndex(Set
<Artifact
> artifacts
,
160 Node fileNode
, Binary fileBinary
) {
161 // List<Artifact> artifacts = new ArrayList<Artifact>();
162 JarInputStream jarIn
= null;
163 BufferedReader reader
= null;
166 jarIn
= new JarInputStream(fileBinary
.getStream());
169 // symbolicName = manifest.getMainAttributes().getValue(
170 // Constants.BUNDLE_SYMBOLICNAME);
171 // version = manifest.getMainAttributes().getValue(
172 // Constants.BUNDLE_VERSION);
174 manifest
= jarIn
.getManifest();
175 if (manifest
== null) {
176 log
.error(fileNode
+ " has no MANIFEST");
181 while ((indexEntry
= jarIn
.getNextJarEntry()) != null) {
182 String entryName
= indexEntry
.getName();
183 if (entryName
.equals(INDEX_FILE_NAME
)) {
189 if (indexEntry
== null)
190 return; // Not a modular definition artifact
192 reader
= new BufferedReader(new InputStreamReader(jarIn
));
194 while ((line
= reader
.readLine()) != null) {
195 StringTokenizer st
= new StringTokenizer(line
, separator
);
196 st
.nextToken(); // moduleName
197 st
.nextToken(); // moduleVersion
198 String relativeUrl
= st
.nextToken();
200 artifacts
.add(AetherUtils
.convertPathToArtifact(relativeUrl
,
202 if (log
.isTraceEnabled())
203 log
.debug("Processed dependency: " + line
);
205 } catch (Exception e
) {
206 throw new SlcException("Cannot list artifacts", e
);
208 IOUtils
.closeQuietly(jarIn
);
209 IOUtils
.closeQuietly(reader
);
213 protected void listModulesFromPomIndex(Set
<Artifact
> artifacts
,
214 Node fileNode
, Binary fileBinary
) {
215 InputStream input
= null;
217 input
= fileBinary
.getStream();
219 DocumentBuilder documentBuilder
= DocumentBuilderFactory
220 .newInstance().newDocumentBuilder();
221 Document doc
= documentBuilder
.parse(input
);
224 Properties props
= new Properties();
225 // props.setProperty("project.version",
226 // pomArtifact.getBaseVersion());
227 NodeList properties
= doc
.getElementsByTagName("properties");
228 if (properties
.getLength() > 0) {
229 NodeList propertiesElems
= properties
.item(0).getChildNodes();
230 for (int i
= 0; i
< propertiesElems
.getLength(); i
++) {
231 if (propertiesElems
.item(i
) instanceof Element
) {
232 Element property
= (Element
) propertiesElems
.item(i
);
233 props
.put(property
.getNodeName(),
234 property
.getTextContent());
239 // full coordinates are under <dependencyManagement><dependencies>
240 NodeList dependencies
= ((Element
) doc
.getElementsByTagName(
241 "dependencyManagement").item(0))
242 .getElementsByTagName("dependency");
243 for (int i
= 0; i
< dependencies
.getLength(); i
++) {
244 Element dependency
= (Element
) dependencies
.item(i
);
245 String groupId
= dependency
.getElementsByTagName("groupId")
246 .item(0).getTextContent().trim();
247 String artifactId
= dependency
248 .getElementsByTagName("artifactId").item(0)
249 .getTextContent().trim();
250 String version
= dependency
.getElementsByTagName("version")
251 .item(0).getTextContent().trim();
252 // if (version.startsWith("${")) {
253 // String versionKey = version.substring(0,
254 // version.length() - 1).substring(2);
255 // if (!props.containsKey(versionKey))
256 // throw new SlcException("Cannot interpret version "
258 // version = props.getProperty(versionKey);
260 // NodeList scopes = dependency.getElementsByTagName("scope");
261 // if (scopes.getLength() > 0
262 // && scopes.item(0).getTextContent().equals("import")) {
264 // gatherPomDependencies(aetherTemplate, artifacts,
265 // new DefaultArtifact(groupId, artifactId, "pom",
268 // TODO: deal with scope?
269 // TODO: deal with type
271 Artifact artifact
= new DefaultArtifact(groupId
, artifactId
,
273 artifacts
.add(artifact
);
276 } catch (Exception e
) {
277 throw new SlcException("Cannot process pom " + fileNode
, e
);
279 IOUtils
.closeQuietly(input
);
283 /** Separator used to parse the tabular file, default is "," */
284 public void setSeparator(String modulesUrlSeparator
) {
285 this.separator
= modulesUrlSeparator
;
288 /** One of the listed artifact */
289 protected static class OsgiArtifact
{
290 private final String category
;
291 private final String symbolicName
;
292 private final String version
;
293 private final String relativeUrl
;
295 public OsgiArtifact(String category
, String symbolicName
,
296 String version
, String relativeUrl
) {
298 this.category
= category
;
299 this.symbolicName
= symbolicName
;
300 this.version
= version
;
301 this.relativeUrl
= relativeUrl
;
304 public String
getCategory() {
308 public String
getSymbolicName() {
312 public String
getVersion() {
316 public String
getRelativeUrl() {