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