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