1 package org
.argeo
.slc
.repo
.maven
;
3 import java
.io
.ByteArrayOutputStream
;
5 import java
.io
.FileInputStream
;
6 import java
.util
.Comparator
;
7 import java
.util
.HashSet
;
8 import java
.util
.Properties
;
10 import java
.util
.TreeSet
;
12 import javax
.jcr
.Binary
;
13 import javax
.jcr
.Node
;
14 import javax
.jcr
.Property
;
15 import javax
.jcr
.Session
;
16 import javax
.jcr
.nodetype
.NodeType
;
17 import javax
.xml
.parsers
.DocumentBuilder
;
18 import javax
.xml
.parsers
.DocumentBuilderFactory
;
20 import org
.apache
.commons
.logging
.Log
;
21 import org
.apache
.commons
.logging
.LogFactory
;
22 import org
.argeo
.jcr
.JcrUtils
;
23 import org
.argeo
.slc
.SlcException
;
24 import org
.argeo
.slc
.aether
.AetherTemplate
;
25 import org
.sonatype
.aether
.artifact
.Artifact
;
26 import org
.sonatype
.aether
.graph
.DependencyNode
;
27 import org
.sonatype
.aether
.util
.artifact
.DefaultArtifact
;
28 import org
.w3c
.dom
.Document
;
29 import org
.w3c
.dom
.Element
;
30 import org
.w3c
.dom
.NodeList
;
32 public class ImportMavenDependencies
implements Runnable
{
33 private final static Log log
= LogFactory
34 .getLog(ImportMavenDependencies
.class);
36 private AetherTemplate aetherTemplate
;
37 private String rootCoordinates
;
38 private Set
<String
> excludedArtifacts
= new HashSet
<String
>();
40 private Session jcrSession
;
41 private String artifactBasePath
= "/slc/repo/artifacts";
44 Set
<Artifact
> artifacts
= resolveDistribution();
45 syncDistribution(artifacts
);
48 public Set
<Artifact
> resolveDistribution() {
50 Artifact pomArtifact
= new DefaultArtifact(rootCoordinates
);
51 Comparator
<Artifact
> artifactComparator
= new Comparator
<Artifact
>() {
52 public int compare(Artifact o1
, Artifact o2
) {
53 return o1
.getArtifactId().compareTo(o2
.getArtifactId());
57 Set
<Artifact
> registeredArtifacts
= new TreeSet
<Artifact
>(
59 parsePom(aetherTemplate
, registeredArtifacts
, pomArtifact
);
60 if (log
.isDebugEnabled())
61 log
.debug("Gathered " + registeredArtifacts
.size()
64 // Resolve and add non-optional dependencies
65 Set
<Artifact
> artifacts
= new TreeSet
<Artifact
>(artifactComparator
);
66 for (Artifact artifact
: registeredArtifacts
) {
68 addArtifact(artifacts
, artifact
);
69 DependencyNode node
= aetherTemplate
70 .resolveDependencies(artifact
);
71 addDependencies(artifacts
, node
);
72 } catch (Exception e
) {
73 log
.error("Could not resolve dependencies of " + artifact
74 + ": " + e
.getCause().getMessage());
79 if (log
.isDebugEnabled())
80 log
.debug("Resolved " + artifacts
.size() + " artifacts");
81 Properties distributionDescriptor
= new Properties();
82 for (Artifact artifact
: artifacts
) {
83 log
.debug(artifact
.getArtifactId() + " ["
84 + artifact
.getVersion() + "]\t(" + artifact
+ ")");
85 distributionDescriptor
.setProperty(artifact
.getArtifactId()
86 + ":" + artifact
.getVersion(), artifact
.toString());
89 ByteArrayOutputStream out
= new ByteArrayOutputStream();
90 distributionDescriptor
.store(out
, "");
91 log
.debug(new String(out
.toByteArray()));
95 } catch (Exception e
) {
96 throw new SlcException("Cannot resolve distribution", e
);
100 protected void syncDistribution(Set
<Artifact
> artifacts
) {
101 Long begin
= System
.currentTimeMillis();
103 JcrUtils
.mkdirs(jcrSession
, artifactBasePath
);
104 for (Artifact artifact
: artifacts
) {
105 String parentPath
= artifactBasePath
+ '/'
106 + artifactParentPath(artifact
);
108 if (!jcrSession
.itemExists(parentPath
)) {
109 parentNode
= JcrUtils
.mkdirs(jcrSession
, parentPath
,
110 NodeType
.NT_FOLDER
, false);
112 parentNode
= jcrSession
.getNode(parentPath
);
115 File file
= artifact
.getFile();
117 if (!parentNode
.hasNode(file
.getName())) {
118 fileNode
= createFileNode(parentNode
, file
);
120 fileNode
= parentNode
.getNode(file
.getName());
124 Long duration
= (System
.currentTimeMillis() - begin
) / 1000;
125 if (log
.isDebugEnabled())
126 log
.debug("Synchronized distribution in " + duration
+ "s");
127 } catch (Exception e
) {
128 throw new SlcException("Cannot synchronize distribution", e
);
132 protected String
artifactParentPath(Artifact artifact
) {
133 return artifact
.getGroupId().replace('.', '/') + '/'
134 + artifact
.getArtifactId() + '/' + artifact
.getVersion();
137 protected Node
createFileNode(Node parentNode
, File file
) {
139 Node fileNode
= parentNode
140 .addNode(file
.getName(), NodeType
.NT_FILE
);
141 Node contentNode
= fileNode
.addNode(Node
.JCR_CONTENT
,
142 NodeType
.NT_RESOURCE
);
143 Binary binary
= jcrSession
.getValueFactory().createBinary(
144 new FileInputStream(file
));
145 contentNode
.setProperty(Property
.JCR_DATA
, binary
);
148 } catch (Exception e
) {
149 throw new SlcException("Cannot create file node based on " + file
150 + " under " + parentNode
, e
);
154 /** Recursively adds non optional dependencies */
155 private void addDependencies(Set
<Artifact
> artifacts
, DependencyNode node
) {
156 for (DependencyNode child
: node
.getChildren()) {
157 if (!child
.getDependency().isOptional()) {
158 addArtifact(artifacts
, child
.getDependency().getArtifact());
159 addDependencies(artifacts
, child
);
164 private void addArtifact(Set
<Artifact
> artifacts
, Artifact artifact
) {
165 if (!excludedArtifacts
.contains(artifact
.getGroupId() + ":"
166 + artifact
.getArtifactId()))
167 artifacts
.add(artifact
);
171 * Directly parses Maven POM XML format in order to find all artifacts
172 * references under the dependency and dependencyManagement tags. This is
173 * meant to migrate existing pom registering a lot of artifacts, not to
174 * replace Maven resolving.
176 protected void parsePom(AetherTemplate aetherTemplate
,
177 Set
<Artifact
> artifacts
, Artifact pomArtifact
) {
178 if (log
.isDebugEnabled())
179 log
.debug("Gather dependencies for " + pomArtifact
);
182 File file
= aetherTemplate
.getResolvedFile(pomArtifact
);
183 DocumentBuilder documentBuilder
= DocumentBuilderFactory
184 .newInstance().newDocumentBuilder();
185 Document doc
= documentBuilder
.parse(file
);
188 Properties props
= new Properties();
189 props
.setProperty("project.version", pomArtifact
.getBaseVersion());
190 NodeList properties
= doc
.getElementsByTagName("properties");
191 if (properties
.getLength() > 0) {
192 NodeList propertiesElems
= properties
.item(0).getChildNodes();
193 for (int i
= 0; i
< propertiesElems
.getLength(); i
++) {
194 if (propertiesElems
.item(i
) instanceof Element
) {
195 Element property
= (Element
) propertiesElems
.item(i
);
196 props
.put(property
.getNodeName(),
197 property
.getTextContent());
202 // dependencies (direct and dependencyManagement)
203 NodeList dependencies
= doc
.getElementsByTagName("dependency");
204 for (int i
= 0; i
< dependencies
.getLength(); i
++) {
205 Element dependency
= (Element
) dependencies
.item(i
);
206 String groupId
= dependency
.getElementsByTagName("groupId")
207 .item(0).getTextContent().trim();
208 String artifactId
= dependency
209 .getElementsByTagName("artifactId").item(0)
210 .getTextContent().trim();
211 String version
= dependency
.getElementsByTagName("version")
212 .item(0).getTextContent().trim();
213 if (version
.startsWith("${")) {
214 String versionKey
= version
.substring(0,
215 version
.length() - 1).substring(2);
216 if (!props
.containsKey(versionKey
))
217 throw new SlcException("Cannot interpret version "
219 version
= props
.getProperty(versionKey
);
221 NodeList scopes
= dependency
.getElementsByTagName("scope");
222 if (scopes
.getLength() > 0
223 && scopes
.item(0).getTextContent().equals("import")) {
225 parsePom(aetherTemplate
, artifacts
, new DefaultArtifact(
226 groupId
, artifactId
, "pom", version
));
228 // TODO: deal with scope?
229 // TODO: deal with type
231 Artifact artifact
= new DefaultArtifact(groupId
,
232 artifactId
, type
, version
);
233 artifacts
.add(artifact
);
236 } catch (Exception e
) {
237 throw new SlcException("Cannot process " + pomArtifact
, e
);
241 public void setAetherTemplate(AetherTemplate aetherTemplate
) {
242 this.aetherTemplate
= aetherTemplate
;
245 public void setExcludedArtifacts(Set
<String
> excludedArtifactIds
) {
246 this.excludedArtifacts
= excludedArtifactIds
;
249 public void setRootCoordinates(String rootCoordinates
) {
250 this.rootCoordinates
= rootCoordinates
;
253 public void setJcrSession(Session jcrSession
) {
254 this.jcrSession
= jcrSession
;