]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java
Working indexation (artifact, jar, osgi) in repo
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / maven / ImportMavenDependencies.java
1 package org.argeo.slc.repo.maven;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.InputStream;
8 import java.util.ArrayList;
9 import java.util.Comparator;
10 import java.util.HashSet;
11 import java.util.List;
12 import java.util.Properties;
13 import java.util.Set;
14 import java.util.TreeSet;
15 import java.util.jar.Attributes;
16 import java.util.jar.Attributes.Name;
17 import java.util.jar.JarInputStream;
18 import java.util.jar.Manifest;
19
20 import javax.jcr.Binary;
21 import javax.jcr.Node;
22 import javax.jcr.NodeIterator;
23 import javax.jcr.Property;
24 import javax.jcr.RepositoryException;
25 import javax.jcr.Session;
26 import javax.jcr.nodetype.NodeType;
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29
30 import org.apache.commons.io.FilenameUtils;
31 import org.apache.commons.io.IOUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.argeo.jcr.JcrUtils;
35 import org.argeo.slc.SlcException;
36 import org.argeo.slc.aether.AetherTemplate;
37 import org.argeo.slc.jcr.SlcNames;
38 import org.argeo.slc.jcr.SlcTypes;
39 import org.argeo.slc.repo.ArtifactIndexer;
40 import org.argeo.slc.repo.RepoConstants;
41 import org.osgi.framework.Constants;
42 import org.osgi.framework.Version;
43 import org.sonatype.aether.artifact.Artifact;
44 import org.sonatype.aether.graph.DependencyNode;
45 import org.sonatype.aether.util.artifact.DefaultArtifact;
46 import org.w3c.dom.Document;
47 import org.w3c.dom.Element;
48 import org.w3c.dom.NodeList;
49
50 public class ImportMavenDependencies implements Runnable {
51 private final static Log log = LogFactory
52 .getLog(ImportMavenDependencies.class);
53
54 private AetherTemplate aetherTemplate;
55 private String rootCoordinates;
56 private Set<String> excludedArtifacts = new HashSet<String>();
57
58 private Session jcrSession;
59 private String artifactBasePath = RepoConstants.ARTIFACTS_BASE_PATH;
60 private String distributionsBasePath = "/slc/repo/distributions";
61 private String distributionName;
62
63 private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
64
65 public void run() {
66 log.debug(jcrSession.getUserID());
67 Set<Artifact> artifacts = resolveDistribution();
68 syncDistribution(artifacts);
69 }
70
71 public Set<Artifact> resolveDistribution() {
72 try {
73 Artifact pomArtifact = new DefaultArtifact(rootCoordinates);
74 Comparator<Artifact> artifactComparator = new Comparator<Artifact>() {
75 public int compare(Artifact o1, Artifact o2) {
76 return o1.getArtifactId().compareTo(o2.getArtifactId());
77 }
78 };
79
80 Set<Artifact> registeredArtifacts = new TreeSet<Artifact>(
81 artifactComparator);
82 parsePom(aetherTemplate, registeredArtifacts, pomArtifact);
83 if (log.isDebugEnabled())
84 log.debug("Gathered " + registeredArtifacts.size()
85 + " artifacts");
86
87 // Resolve and add non-optional dependencies
88 Set<Artifact> artifacts = new TreeSet<Artifact>(artifactComparator);
89 for (Artifact artifact : registeredArtifacts) {
90 try {
91 addArtifact(artifacts, artifact);
92 DependencyNode node = aetherTemplate
93 .resolveDependencies(artifact);
94 addDependencies(artifacts, node);
95 } catch (Exception e) {
96 log.error("Could not resolve dependencies of " + artifact
97 + ": " + e.getCause().getMessage());
98 }
99
100 }
101
102 if (log.isDebugEnabled())
103 log.debug("Resolved " + artifacts.size() + " artifacts");
104 Properties distributionDescriptor = new Properties();
105 for (Artifact artifact : artifacts) {
106 log.debug(artifact.getArtifactId() + " ["
107 + artifact.getVersion() + "]\t(" + artifact + ")");
108 distributionDescriptor.setProperty(artifact.getArtifactId()
109 + ":" + artifact.getVersion(), artifact.toString());
110 }
111
112 ByteArrayOutputStream out = new ByteArrayOutputStream();
113 distributionDescriptor.store(out, "");
114 log.debug(new String(out.toByteArray()));
115 out.close();
116
117 return artifacts;
118 } catch (Exception e) {
119 throw new SlcException("Cannot resolve distribution", e);
120 }
121 }
122
123 protected void syncDistribution(Set<Artifact> artifacts) {
124 Long begin = System.currentTimeMillis();
125 try {
126 JcrUtils.mkdirs(jcrSession, artifactBasePath);
127 JcrUtils.mkdirs(jcrSession, distributionsBasePath + '/'
128 + distributionName);
129 artifacts: for (Artifact artifact : artifacts) {
130 File file = artifact.getFile();
131 if (file == null) {
132 log.warn("File not found for " + artifact);
133
134 file = artifactToFile(artifact);
135
136 if (!file.exists()) {
137 log.warn("Generated file " + file + " for " + artifact
138 + " does not exist");
139 continue artifacts;
140 }
141 }
142
143 try {
144 String parentPath = artifactBasePath + '/'
145 + artifactParentPath(artifact);
146 Node parentNode;
147 if (!jcrSession.itemExists(parentPath)) {
148 parentNode = JcrUtils.mkdirs(jcrSession, parentPath,
149 NodeType.NT_FOLDER);
150 } else {
151 parentNode = jcrSession.getNode(parentPath);
152 }
153
154 Node fileNode;
155 if (!parentNode.hasNode(file.getName())) {
156 fileNode = createFileNode(parentNode, file);
157 } else {
158 fileNode = parentNode.getNode(file.getName());
159 }
160
161 if (artifactIndexer.support(fileNode.getPath()))
162 artifactIndexer.index(fileNode);
163 if (fileNode.isNodeType(SlcTypes.SLC_JAR_FILE)) {
164 processOsgiBundle(fileNode);
165 }
166 jcrSession.save();
167
168 if (!jcrSession
169 .itemExists(bundleDistributionPath(fileNode))
170 && fileNode
171 .isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT))
172 jcrSession.getWorkspace().clone(
173 jcrSession.getWorkspace().getName(),
174 fileNode.getPath(),
175 bundleDistributionPath(fileNode), false);
176
177 if (log.isDebugEnabled())
178 log.debug("Synchronized " + fileNode);
179 } catch (Exception e) {
180 log.error("Could not synchronize " + artifact, e);
181 jcrSession.refresh(false);
182 throw e;
183 }
184 }
185
186 Long duration = (System.currentTimeMillis() - begin) / 1000;
187 if (log.isDebugEnabled())
188 log.debug("Synchronized distribution in " + duration + "s");
189 } catch (Exception e) {
190 throw new SlcException("Cannot synchronize distribution", e);
191 }
192 }
193
194 protected String artifactParentPath(Artifact artifact) {
195 return artifact.getGroupId().replace('.', '/') + '/'
196 + artifact.getArtifactId() + '/' + artifact.getVersion();
197 }
198
199 protected String bundleDistributionPath(Node fileNode) {
200 try {
201 return distributionsBasePath
202 + '/'
203 + distributionName
204 + '/'
205 + fileNode.getProperty(SlcNames.SLC_SYMBOLIC_NAME)
206 .getString()
207 + '_'
208 + fileNode.getProperty(SlcNames.SLC_BUNDLE_VERSION)
209 .getString();
210 } catch (RepositoryException e) {
211 throw new SlcException("Cannot create distribution path for "
212 + fileNode, e);
213 }
214 }
215
216 protected File artifactToFile(Artifact artifact) {
217 return new File(System.getProperty("user.home")
218 + File.separator
219 + ".m2"
220 + File.separator
221 + "repository"
222 + File.separator
223 + artifact.getGroupId().replace('.', File.separatorChar)
224 + File.separator
225 + artifact.getArtifactId()
226 + File.separator
227 + artifact.getVersion()
228 + File.separator
229 + artifact.getArtifactId()
230 + '-'
231 + artifact.getVersion()
232 + (artifact.getClassifier().equals("") ? ""
233 : '-' + artifact.getClassifier()) + '.'
234 + artifact.getExtension());
235 }
236
237 protected void processOsgiBundle(Node fileNode) {
238 Binary manifestBinary = null;
239 InputStream manifestIn = null;
240 try {
241 manifestBinary = fileNode.getProperty(SlcNames.SLC_MANIFEST)
242 .getBinary();
243 manifestIn = manifestBinary.getStream();
244 Manifest manifest = new Manifest(manifestIn);
245 Attributes attrs = manifest.getMainAttributes();
246
247 if (log.isTraceEnabled())
248 for (Object key : attrs.keySet())
249 log.trace(key + ": " + attrs.getValue(key.toString()));
250
251 if (!attrs.containsKey(new Name(Constants.BUNDLE_SYMBOLICNAME))) {
252 log.warn(fileNode + " is not an OSGi bundle");
253 return;// not an osgi bundle
254 }
255
256 fileNode.addMixin(SlcTypes.SLC_BUNDLE_ARTIFACT);
257
258 // symbolic name
259 String symbolicName = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME);
260 // make sure there is no directive
261 symbolicName = symbolicName.split(";")[0];
262 fileNode.setProperty(SlcNames.SLC_SYMBOLIC_NAME, symbolicName);
263
264 // direct mapping
265 addAttr(Constants.BUNDLE_SYMBOLICNAME, fileNode, attrs);
266 addAttr(Constants.BUNDLE_NAME, fileNode, attrs);
267 addAttr(Constants.BUNDLE_DESCRIPTION, fileNode, attrs);
268 addAttr(Constants.BUNDLE_MANIFESTVERSION, fileNode, attrs);
269 addAttr(Constants.BUNDLE_CATEGORY, fileNode, attrs);
270 addAttr(Constants.BUNDLE_ACTIVATIONPOLICY, fileNode, attrs);
271 addAttr(Constants.BUNDLE_COPYRIGHT, fileNode, attrs);
272 addAttr(Constants.BUNDLE_VENDOR, fileNode, attrs);
273 addAttr("Bundle-License", fileNode, attrs);
274 addAttr(Constants.BUNDLE_DOCURL, fileNode, attrs);
275 addAttr(Constants.BUNDLE_CONTACTADDRESS, fileNode, attrs);
276 addAttr(Constants.BUNDLE_ACTIVATOR, fileNode, attrs);
277 addAttr(Constants.BUNDLE_UPDATELOCATION, fileNode, attrs);
278 addAttr(Constants.BUNDLE_LOCALIZATION, fileNode, attrs);
279
280 // required execution environment
281 if (attrs.containsKey(new Name(
282 Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)))
283 fileNode.setProperty(
284 SlcNames.SLC_
285 + Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT,
286 attrs.getValue(
287 Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)
288 .split(","));
289
290 // bundle classpath
291 if (attrs.containsKey(new Name(Constants.BUNDLE_CLASSPATH)))
292 fileNode.setProperty(
293 SlcNames.SLC_ + Constants.BUNDLE_CLASSPATH, attrs
294 .getValue(Constants.BUNDLE_CLASSPATH)
295 .split(","));
296
297 // version
298 Version version = new Version(
299 attrs.getValue(Constants.BUNDLE_VERSION));
300 fileNode.setProperty(SlcNames.SLC_BUNDLE_VERSION,
301 version.toString());
302 cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.BUNDLE_VERSION);
303 Node bundleVersionNode = fileNode.addNode(SlcNames.SLC_
304 + Constants.BUNDLE_VERSION, SlcTypes.SLC_OSGI_VERSION);
305 mapOsgiVersion(version, bundleVersionNode);
306
307 // fragment
308 cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.FRAGMENT_HOST);
309 if (attrs.containsKey(new Name(Constants.FRAGMENT_HOST))) {
310 String fragmentHost = attrs.getValue(Constants.FRAGMENT_HOST);
311 String[] tokens = fragmentHost.split(";");
312 Node node = fileNode.addNode(SlcNames.SLC_
313 + Constants.FRAGMENT_HOST, SlcTypes.SLC_FRAGMENT_HOST);
314 node.setProperty(SlcNames.SLC_SYMBOLIC_NAME, tokens[0]);
315 for (int i = 1; i < tokens.length; i++) {
316 if (tokens[i]
317 .startsWith(Constants.BUNDLE_VERSION_ATTRIBUTE)) {
318 node.setProperty(SlcNames.SLC_BUNDLE_VERSION,
319 attributeValue(tokens[i]));
320 }
321 }
322 }
323
324 // imported packages
325 cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.IMPORT_PACKAGE);
326 if (attrs.containsKey(new Name(Constants.IMPORT_PACKAGE))) {
327 String importPackages = attrs
328 .getValue(Constants.IMPORT_PACKAGE);
329 List<String> packages = parsePackages(importPackages);
330 for (String pkg : packages) {
331 String[] tokens = pkg.split(";");
332 Node node = fileNode.addNode(SlcNames.SLC_
333 + Constants.IMPORT_PACKAGE,
334 SlcTypes.SLC_IMPORTED_PACKAGE);
335 node.setProperty(SlcNames.SLC_NAME, tokens[0]);
336 for (int i = 1; i < tokens.length; i++) {
337 if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
338 node.setProperty(SlcNames.SLC_VERSION,
339 attributeValue(tokens[i]));
340 } else if (tokens[i]
341 .startsWith(Constants.RESOLUTION_DIRECTIVE)) {
342 node.setProperty(
343 SlcNames.SLC_OPTIONAL,
344 directiveValue(tokens[i]).equals(
345 Constants.RESOLUTION_OPTIONAL));
346 }
347 }
348 }
349 }
350
351 // dynamic import package
352 cleanSubNodes(fileNode, SlcNames.SLC_
353 + Constants.DYNAMICIMPORT_PACKAGE);
354 if (attrs.containsKey(new Name(Constants.DYNAMICIMPORT_PACKAGE))) {
355 String importPackages = attrs
356 .getValue(Constants.DYNAMICIMPORT_PACKAGE);
357 List<String> packages = parsePackages(importPackages);
358 for (String pkg : packages) {
359 String[] tokens = pkg.split(";");
360 Node node = fileNode.addNode(SlcNames.SLC_
361 + Constants.DYNAMICIMPORT_PACKAGE,
362 SlcTypes.SLC_DYNAMIC_IMPORTED_PACKAGE);
363 node.setProperty(SlcNames.SLC_NAME, tokens[0]);
364 for (int i = 1; i < tokens.length; i++) {
365 if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
366 node.setProperty(SlcNames.SLC_VERSION,
367 attributeValue(tokens[i]));
368 }
369 }
370 }
371 }
372
373 // exported packages
374 cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.EXPORT_PACKAGE);
375 if (attrs.containsKey(new Name(Constants.EXPORT_PACKAGE))) {
376 String exportPackages = attrs
377 .getValue(Constants.EXPORT_PACKAGE);
378 List<String> packages = parsePackages(exportPackages);
379 for (String pkg : packages) {
380 String[] tokens = pkg.split(";");
381 Node node = fileNode.addNode(SlcNames.SLC_
382 + Constants.EXPORT_PACKAGE,
383 SlcTypes.SLC_EXPORTED_PACKAGE);
384 node.setProperty(SlcNames.SLC_NAME, tokens[0]);
385 // TODO: are these cleans really necessary?
386 cleanSubNodes(node, SlcNames.SLC_USES);
387 cleanSubNodes(node, SlcNames.SLC_VERSION);
388 for (int i = 1; i < tokens.length; i++) {
389 if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
390 String versionStr = attributeValue(tokens[i]);
391 Node versionNode = node.addNode(
392 SlcNames.SLC_VERSION,
393 SlcTypes.SLC_OSGI_VERSION);
394 mapOsgiVersion(new Version(versionStr), versionNode);
395 } else if (tokens[i]
396 .startsWith(Constants.USES_DIRECTIVE)) {
397 String usedPackages = directiveValue(tokens[i]);
398 // log.debug("uses='" + usedPackages + "'");
399 for (String usedPackage : usedPackages.split(",")) {
400 // log.debug("usedPackage='" + usedPackage +
401 // "'");
402 Node usesNode = node.addNode(SlcNames.SLC_USES,
403 SlcTypes.SLC_JAVA_PACKAGE);
404 usesNode.setProperty(SlcNames.SLC_NAME,
405 usedPackage);
406 }
407 }
408 }
409 }
410 }
411
412 // required bundle
413 cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.REQUIRE_BUNDLE);
414 if (attrs.containsKey(new Name(Constants.REQUIRE_BUNDLE))) {
415 String requireBundle = attrs.getValue(Constants.REQUIRE_BUNDLE);
416 String[] bundles = requireBundle.split(",");
417 for (String bundle : bundles) {
418 String[] tokens = bundle.split(";");
419 Node node = fileNode.addNode(SlcNames.SLC_
420 + Constants.REQUIRE_BUNDLE,
421 SlcTypes.SLC_REQUIRED_BUNDLE);
422 node.setProperty(SlcNames.SLC_SYMBOLIC_NAME, tokens[0]);
423 for (int i = 1; i < tokens.length; i++) {
424 if (tokens[i]
425 .startsWith(Constants.BUNDLE_VERSION_ATTRIBUTE)) {
426 node.setProperty(SlcNames.SLC_BUNDLE_VERSION,
427 attributeValue(tokens[i]));
428 } else if (tokens[i]
429 .startsWith(Constants.RESOLUTION_DIRECTIVE)) {
430 node.setProperty(
431 SlcNames.SLC_OPTIONAL,
432 directiveValue(tokens[i]).equals(
433 Constants.RESOLUTION_OPTIONAL));
434 }
435 }
436 }
437 }
438 } catch (Exception e) {
439 throw new SlcException("Cannot process OSGi bundle " + fileNode, e);
440 } finally {
441 if (manifestBinary != null)
442 manifestBinary.dispose();
443 IOUtils.closeQuietly(manifestIn);
444 }
445 }
446
447 /** Parse package list with nested directive with ',' */
448 private List<String> parsePackages(String str) {
449 List<String> res = new ArrayList<String>();
450 StringBuffer curr = new StringBuffer("");
451 boolean in = false;
452 for (char c : str.toCharArray()) {
453 if (c == ',') {
454 if (!in) {
455 res.add(curr.toString());
456 curr = new StringBuffer("");
457 }
458 } else if (c == '\"') {
459 in = !in;
460 curr.append(c);
461 } else {
462 curr.append(c);
463 }
464 }
465 res.add(curr.toString());
466 log.debug(res);
467 return res;
468 }
469
470 private void addAttr(String key, Node node, Attributes attrs)
471 throws RepositoryException {
472 addAttr(new Name(key), node, attrs);
473 }
474
475 private void addAttr(Name key, Node node, Attributes attrs)
476 throws RepositoryException {
477 if (attrs.containsKey(key)) {
478 String value = attrs.getValue(key);
479 node.setProperty(SlcNames.SLC_ + key, value);
480 }
481 }
482
483 private void cleanSubNodes(Node node, String name)
484 throws RepositoryException {
485 if (node.hasNode(name)) {
486 NodeIterator nit = node.getNodes(name);
487 while (nit.hasNext())
488 nit.nextNode().remove();
489 }
490 }
491
492 protected void mapOsgiVersion(Version version, Node versionNode)
493 throws RepositoryException {
494 versionNode.setProperty(SlcNames.SLC_AS_STRING, version.toString());
495 versionNode.setProperty(SlcNames.SLC_MAJOR, version.getMajor());
496 versionNode.setProperty(SlcNames.SLC_MINOR, version.getMinor());
497 versionNode.setProperty(SlcNames.SLC_MICRO, version.getMicro());
498 if (!version.getQualifier().equals(""))
499 versionNode.setProperty(SlcNames.SLC_QUALIFIER,
500 version.getQualifier());
501 }
502
503 private String attributeValue(String str) {
504 return extractValue(str, "=");
505 }
506
507 private String directiveValue(String str) {
508 return extractValue(str, ":=");
509 }
510
511 private String extractValue(String str, String eq) {
512 String[] tokens = str.split(eq);
513 // String key = tokens[0];
514 String value = tokens[1].trim();
515 // TODO: optimize?
516 if (value.startsWith("\""))
517 value = value.substring(1);
518 if (value.endsWith("\""))
519 value = value.substring(0, value.length() - 1);
520 return value;
521 }
522
523 protected Node createFileNode(Node parentNode, File file) {
524 Binary binary = null;
525 try {
526 Node fileNode = parentNode
527 .addNode(file.getName(), NodeType.NT_FILE);
528 Node contentNode = fileNode.addNode(Node.JCR_CONTENT,
529 NodeType.NT_RESOURCE);
530 binary = jcrSession.getValueFactory().createBinary(
531 new FileInputStream(file));
532 contentNode.setProperty(Property.JCR_DATA, binary);
533 // jar file
534 if (FilenameUtils.isExtension(file.getName(), "jar")) {
535 JarInputStream jarIn = null;
536 ByteArrayOutputStream bo = null;
537 ByteArrayInputStream bi = null;
538 Binary manifestBinary = null;
539 try {
540 jarIn = new JarInputStream(binary.getStream());
541 Manifest manifest = jarIn.getManifest();
542 bo = new ByteArrayOutputStream();
543 manifest.write(bo);
544 bi = new ByteArrayInputStream(bo.toByteArray());
545 manifestBinary = jcrSession.getValueFactory().createBinary(
546 bi);
547 fileNode.addMixin(SlcTypes.SLC_JAR_FILE);
548 fileNode.setProperty(SlcNames.SLC_MANIFEST, manifestBinary);
549 Attributes attrs = manifest.getMainAttributes();
550 addAttr(Attributes.Name.MANIFEST_VERSION, fileNode, attrs);
551 addAttr(Attributes.Name.SIGNATURE_VERSION, fileNode, attrs);
552 addAttr(Attributes.Name.CLASS_PATH, fileNode, attrs);
553 addAttr(Attributes.Name.MAIN_CLASS, fileNode, attrs);
554 addAttr(Attributes.Name.EXTENSION_NAME, fileNode, attrs);
555 addAttr(Attributes.Name.IMPLEMENTATION_VERSION, fileNode,
556 attrs);
557 addAttr(Attributes.Name.IMPLEMENTATION_VENDOR, fileNode,
558 attrs);
559 addAttr(Attributes.Name.IMPLEMENTATION_VENDOR_ID, fileNode,
560 attrs);
561 addAttr(Attributes.Name.SPECIFICATION_TITLE, fileNode,
562 attrs);
563 addAttr(Attributes.Name.SPECIFICATION_VERSION, fileNode,
564 attrs);
565 addAttr(Attributes.Name.SPECIFICATION_VENDOR, fileNode,
566 attrs);
567 addAttr(Attributes.Name.SEALED, fileNode, attrs);
568 } finally {
569 if (manifestBinary != null)
570 manifestBinary.dispose();
571 IOUtils.closeQuietly(bi);
572 IOUtils.closeQuietly(bo);
573 IOUtils.closeQuietly(jarIn);
574 }
575 }
576 return fileNode;
577 } catch (Exception e) {
578 throw new SlcException("Cannot create file node based on " + file
579 + " under " + parentNode, e);
580 } finally {
581 if (binary != null)
582 binary.dispose();
583 }
584 }
585
586 /** Recursively adds non optional dependencies */
587 private void addDependencies(Set<Artifact> artifacts, DependencyNode node) {
588 for (DependencyNode child : node.getChildren()) {
589 if (!child.getDependency().isOptional()) {
590 addArtifact(artifacts, child.getDependency().getArtifact());
591 addDependencies(artifacts, child);
592 }
593 }
594 }
595
596 private void addArtifact(Set<Artifact> artifacts, Artifact artifact) {
597 if (!excludedArtifacts.contains(artifact.getGroupId() + ":"
598 + artifact.getArtifactId()))
599 artifacts.add(artifact);
600 }
601
602 /**
603 * Directly parses Maven POM XML format in order to find all artifacts
604 * references under the dependency and dependencyManagement tags. This is
605 * meant to migrate existing pom registering a lot of artifacts, not to
606 * replace Maven resolving.
607 */
608 protected void parsePom(AetherTemplate aetherTemplate,
609 Set<Artifact> artifacts, Artifact pomArtifact) {
610 if (log.isDebugEnabled())
611 log.debug("Gather dependencies for " + pomArtifact);
612
613 try {
614 File file = aetherTemplate.getResolvedFile(pomArtifact);
615 DocumentBuilder documentBuilder = DocumentBuilderFactory
616 .newInstance().newDocumentBuilder();
617 Document doc = documentBuilder.parse(file);
618
619 // properties
620 Properties props = new Properties();
621 props.setProperty("project.version", pomArtifact.getBaseVersion());
622 NodeList properties = doc.getElementsByTagName("properties");
623 if (properties.getLength() > 0) {
624 NodeList propertiesElems = properties.item(0).getChildNodes();
625 for (int i = 0; i < propertiesElems.getLength(); i++) {
626 if (propertiesElems.item(i) instanceof Element) {
627 Element property = (Element) propertiesElems.item(i);
628 props.put(property.getNodeName(),
629 property.getTextContent());
630 }
631 }
632 }
633
634 // dependencies (direct and dependencyManagement)
635 NodeList dependencies = doc.getElementsByTagName("dependency");
636 for (int i = 0; i < dependencies.getLength(); i++) {
637 Element dependency = (Element) dependencies.item(i);
638 String groupId = dependency.getElementsByTagName("groupId")
639 .item(0).getTextContent().trim();
640 String artifactId = dependency
641 .getElementsByTagName("artifactId").item(0)
642 .getTextContent().trim();
643 String version = dependency.getElementsByTagName("version")
644 .item(0).getTextContent().trim();
645 if (version.startsWith("${")) {
646 String versionKey = version.substring(0,
647 version.length() - 1).substring(2);
648 if (!props.containsKey(versionKey))
649 throw new SlcException("Cannot interpret version "
650 + version);
651 version = props.getProperty(versionKey);
652 }
653 NodeList scopes = dependency.getElementsByTagName("scope");
654 if (scopes.getLength() > 0
655 && scopes.item(0).getTextContent().equals("import")) {
656 // recurse
657 parsePom(aetherTemplate, artifacts, new DefaultArtifact(
658 groupId, artifactId, "pom", version));
659 } else {
660 // TODO: deal with scope?
661 // TODO: deal with type
662 String type = "jar";
663 Artifact artifact = new DefaultArtifact(groupId,
664 artifactId, type, version);
665 artifacts.add(artifact);
666 }
667 }
668 } catch (Exception e) {
669 throw new SlcException("Cannot process " + pomArtifact, e);
670 }
671 }
672
673 public void setAetherTemplate(AetherTemplate aetherTemplate) {
674 this.aetherTemplate = aetherTemplate;
675 }
676
677 public void setExcludedArtifacts(Set<String> excludedArtifactIds) {
678 this.excludedArtifacts = excludedArtifactIds;
679 }
680
681 public void setRootCoordinates(String rootCoordinates) {
682 this.rootCoordinates = rootCoordinates;
683 }
684
685 public void setJcrSession(Session jcrSession) {
686 this.jcrSession = jcrSession;
687 }
688
689 public void setDistributionName(String distributionName) {
690 this.distributionName = distributionName;
691 }
692
693 }