2 * Copyright (C) 2007-2012 Mathieu Baudier
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.repo
.maven
;
18 import java
.io
.ByteArrayOutputStream
;
20 import java
.util
.Comparator
;
21 import java
.util
.HashSet
;
22 import java
.util
.Properties
;
24 import java
.util
.TreeSet
;
26 import javax
.jcr
.Node
;
27 import javax
.jcr
.NodeIterator
;
28 import javax
.jcr
.Repository
;
29 import javax
.jcr
.Session
;
30 import javax
.jcr
.nodetype
.NodeType
;
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
.NameVersion
;
37 import org
.argeo
.slc
.SlcException
;
38 import org
.argeo
.slc
.aether
.AetherTemplate
;
39 import org
.argeo
.slc
.repo
.ArtifactIndexer
;
40 import org
.argeo
.slc
.repo
.JarFileIndexer
;
41 import org
.argeo
.slc
.repo
.RepoConstants
;
42 import org
.argeo
.slc
.repo
.RepoUtils
;
43 import org
.sonatype
.aether
.artifact
.Artifact
;
44 import org
.sonatype
.aether
.graph
.DependencyNode
;
45 import org
.sonatype
.aether
.util
.artifact
.DefaultArtifact
;
48 * Import all the dependencies listed in a POM and their dependency graphs to a
51 public class ImportMavenDependencies
implements Runnable
{
52 private final static Log log
= LogFactory
53 .getLog(ImportMavenDependencies
.class);
55 private AetherTemplate aetherTemplate
;
56 private String rootCoordinates
= "org.argeo.dep:versions-all:pom:1.2.0";
57 private String distCoordinates
= "org.argeo.tp:dist:pom:1.3.0";
58 private Set
<String
> excludedArtifacts
= new HashSet
<String
>();
60 private Repository repository
;
61 private String workspace
;
63 private String artifactBasePath
= RepoConstants
.ARTIFACTS_BASE_PATH
;
65 private ArtifactIndexer artifactIndexer
= new ArtifactIndexer();
66 private JarFileIndexer jarFileIndexer
= new JarFileIndexer();
67 private Comparator
<Artifact
> artifactComparator
= new Comparator
<Artifact
>() {
68 public int compare(Artifact o1
, Artifact o2
) {
69 return o1
.getArtifactId().compareTo(o2
.getArtifactId());
75 Set
<Artifact
> artifacts
= resolveDistribution();
81 void sync(Set
<Artifact
> artifacts
) {
82 Session session
= null;
84 session
= JcrUtils
.loginOrCreateWorkspace(repository
, workspace
);
86 NodeIterator nit
= session
.getNode(artifactBasePath
).getNodes();
87 while (nit
.hasNext()) {
88 Node node
= nit
.nextNode();
89 if (node
.isNodeType(NodeType
.NT_FOLDER
)
90 || node
.isNodeType(NodeType
.NT_UNSTRUCTURED
))
94 syncDistribution(session
, artifacts
);
95 } catch (Exception e
) {
96 throw new SlcException("Cannot import distribution", e
);
98 JcrUtils
.logoutQuietly(session
);
103 * Generate a POM with all the artifacts declared in root coordinates as
104 * dependencies AND in dependency management.
106 void createDistPom() {
108 Artifact pomArtifact
= new DefaultArtifact(rootCoordinates
);
110 Set
<Artifact
> registeredArtifacts
= new TreeSet
<Artifact
>(
112 MavenConventionsUtils
.gatherPomDependencies(aetherTemplate
,
113 registeredArtifacts
, pomArtifact
);
114 Artifact sdkArtifact
= new DefaultArtifact(distCoordinates
);
115 String sdkPom
= MavenConventionsUtils
.artifactsAsDependencyPom(
116 sdkArtifact
, registeredArtifacts
);
117 if (log
.isDebugEnabled())
118 log
.debug("Gathered " + registeredArtifacts
.size()
119 + " artifacts:\n" + sdkPom
);
120 } catch (Exception e
) {
121 throw new SlcException("Cannot resolve distribution", e
);
125 /** Returns all transitive dependencies of dist POM */
126 private Set
<Artifact
> resolveDistribution() {
128 Artifact distArtifact
= new DefaultArtifact(distCoordinates
);
129 Set
<Artifact
> artifacts
= new TreeSet
<Artifact
>(artifactComparator
);
131 DependencyNode node
= aetherTemplate
132 .resolveDependencies(distArtifact
);
133 addDependencies(artifacts
, node
, null);
135 if (log
.isDebugEnabled()) {
136 log
.debug("Resolved " + artifacts
.size() + " artifacts");
138 // Properties distributionDescriptor =
139 // generateDistributionDescriptor(artifacts);
140 // ByteArrayOutputStream out = new ByteArrayOutputStream();
141 // distributionDescriptor.store(out, "");
142 // log.debug(new String(out.toByteArray()));
147 * for (Artifact artifact : registeredArtifacts) { try { Boolean
148 * wasAdded = addArtifact(artifacts, artifact); if (wasAdded) {
149 * DependencyNode node = aetherTemplate
150 * .resolveDependencies(artifact); addDependencies(artifacts, node,
151 * null); } } catch (Exception e) {
152 * log.error("Could not resolve dependencies of " + artifact + ": "
153 * + e.getCause().getMessage()); }
157 * if (log.isDebugEnabled()) log.debug("Resolved " +
158 * artifacts.size() + " artifacts");
160 * // distribution descriptor // Properties distributionDescriptor =
161 * // generateDistributionDescriptor(artifacts); //
162 * ByteArrayOutputStream out = new ByteArrayOutputStream(); //
163 * distributionDescriptor.store(out, ""); // log.debug(new
164 * String(out.toByteArray())); // out.close();
167 } catch (Exception e
) {
168 throw new SlcException("Cannot resolve distribution", e
);
172 protected Properties
generateDistributionDescriptor(Set
<Artifact
> artifacts
) {
173 Properties distributionDescriptor
= new Properties();
174 for (Artifact artifact
: artifacts
) {
175 log
.debug(artifact
.getArtifactId() + " [" + artifact
.getVersion()
176 + "]\t(" + artifact
+ ")");
177 distributionDescriptor
.setProperty(artifact
.getArtifactId() + ":"
178 + artifact
.getVersion(), artifact
.toString());
180 return distributionDescriptor
;
183 /** Write artifacts to the target workspace, skipping excluded ones */
184 protected void syncDistribution(Session jcrSession
, Set
<Artifact
> artifacts
) {
185 Set
<Artifact
> artifactsWithoutSources
= new TreeSet
<Artifact
>(
187 Long begin
= System
.currentTimeMillis();
189 JcrUtils
.mkdirs(jcrSession
, artifactBasePath
, NodeType
.NT_FOLDER
,
190 NodeType
.NT_FOLDER
, false);
191 artifacts
: for (Artifact artifact
: artifacts
) {
193 if (excludedArtifacts
.contains(artifact
.getGroupId() + ":"
194 + artifact
.getArtifactId())) {
195 if (log
.isDebugEnabled())
196 log
.debug("Exclude " + artifact
);
200 File jarFile
= MavenConventionsUtils
.artifactToFile(artifact
);
201 if (!jarFile
.exists()) {
202 log
.warn("Generated file " + jarFile
+ " for " + artifact
203 + " does not exist");
206 artifact
.setFile(jarFile
);
209 String parentPath
= MavenConventionsUtils
210 .artifactParentPath(artifactBasePath
, artifact
);
212 if (!jcrSession
.itemExists(parentPath
))
213 parentNode
= JcrUtils
.mkdirs(jcrSession
, parentPath
,
214 NodeType
.NT_FOLDER
, NodeType
.NT_FOLDER
, false);
216 parentNode
= jcrSession
.getNode(parentPath
);
219 if (!parentNode
.hasNode(jarFile
.getName())) {
220 fileNode
= createFileNode(parentNode
, jarFile
);
222 fileNode
= parentNode
.getNode(jarFile
.getName());
225 if (artifactIndexer
.support(fileNode
.getPath()))
226 artifactIndexer
.index(fileNode
);
227 if (jarFileIndexer
.support(fileNode
.getPath()))
228 jarFileIndexer
.index(fileNode
);
231 addPdeSource(jcrSession
, artifact
, jarFile
,
232 artifactsWithoutSources
);
235 if (log
.isDebugEnabled())
236 log
.debug("Synchronized " + fileNode
);
237 } catch (Exception e
) {
238 log
.error("Could not synchronize " + artifact
, e
);
239 jcrSession
.refresh(false);
244 Long duration
= (System
.currentTimeMillis() - begin
) / 1000;
245 if (log
.isDebugEnabled()) {
246 log
.debug("Synchronized distribution in " + duration
+ "s");
247 log
.debug("The following artifacts have no sources:");
248 for (Artifact artifact
: artifactsWithoutSources
) {
252 } catch (Exception e
) {
253 throw new SlcException("Cannot synchronize distribution", e
);
257 /** Try to add PDE sources */
258 private void addPdeSource(Session session
, Artifact artifact
,
259 File artifactFile
, Set
<Artifact
> artifactsWithoutSources
) {
260 ByteArrayOutputStream out
= new ByteArrayOutputStream();
262 File origSourceFile
= null;
263 Artifact origSourceArtifact
= new DefaultArtifact(
264 artifact
.getGroupId(), artifact
.getArtifactId(), "sources",
265 artifact
.getExtension(), artifact
.getVersion());
266 Artifact targetSourceArtifact
= new DefaultArtifact(
267 artifact
.getGroupId(),
268 artifact
.getArtifactId() + ".source",
269 artifact
.getExtension(), artifact
.getVersion());
271 origSourceFile
= aetherTemplate
272 .getResolvedFile(origSourceArtifact
);
273 } catch (Exception e
) {
274 // also try artifact following the conventions
275 origSourceArtifact
= targetSourceArtifact
;
276 origSourceFile
= aetherTemplate
277 .getResolvedFile(origSourceArtifact
);
280 String sourceParentPath
= MavenConventionsUtils
.artifactParentPath(
281 artifactBasePath
, targetSourceArtifact
);
282 Node sourceParentNode
= JcrUtils
.mkdirs(session
, sourceParentPath
,
284 NameVersion bundleNameVersion
= RepoUtils
285 .readNameVersion(artifactFile
);
286 RepoUtils
.packagesAsPdeSource(origSourceFile
, bundleNameVersion
,
288 String targetSourceFileName
= MavenConventionsUtils
289 .artifactFileName(targetSourceArtifact
);
290 JcrUtils
.copyBytesAsFile(sourceParentNode
, targetSourceFileName
,
292 } catch (Exception e
) {
293 log
.error("Cannot add PDE source for " + artifact
+ ": " + e
);
294 artifactsWithoutSources
.add(artifact
);
296 IOUtils
.closeQuietly(out
);
300 private Node
createFileNode(Node parentNode
, File file
) {
301 return JcrUtils
.copyFile(parentNode
, file
);
304 /** Recursively adds non optional dependencies */
305 private void addDependencies(Set
<Artifact
> artifacts
, DependencyNode node
,
307 // if (artifacts.contains(node.getDependency().getArtifact()))
309 String currentArtifactId
= node
.getDependency().getArtifact()
311 if (log
.isDebugEnabled()) {
312 log
.debug("# Add dependency for " + currentArtifactId
);
313 if (ancestors
!= null)
314 log
.debug(ancestors
);
316 for (DependencyNode child
: node
.getChildren()) {
317 if (!child
.getDependency().isOptional()) {
318 if (willAdd(child
.getDependency().getArtifact())) {
319 addArtifact(artifacts
, child
.getDependency().getArtifact());
320 addDependencies(artifacts
, child
, currentArtifactId
+ "\n"
321 + (ancestors
!= null ? ancestors
: ""));
327 /** @return whether it was added */
328 private Boolean
addArtifact(Set
<Artifact
> artifacts
, Artifact artifact
) {
329 Boolean willAdd
= willAdd(artifact
);
331 artifacts
.add(artifact
);
333 log
.info("Skip " + artifact
);
337 private Boolean
willAdd(Artifact artifact
) {
338 Boolean willAdd
= true;
339 if (excludedArtifacts
.contains(artifact
.getGroupId() + ":"
340 + artifact
.getArtifactId()))
342 else if (excludedArtifacts
.contains(artifact
.getGroupId() + ":*"))
347 public void setAetherTemplate(AetherTemplate aetherTemplate
) {
348 this.aetherTemplate
= aetherTemplate
;
351 public void setExcludedArtifacts(Set
<String
> excludedArtifactIds
) {
352 this.excludedArtifacts
= excludedArtifactIds
;
355 public void setRootCoordinates(String rootCoordinates
) {
356 this.rootCoordinates
= rootCoordinates
;
359 public void setRepository(Repository repository
) {
360 this.repository
= repository
;
363 public void setWorkspace(String workspace
) {
364 this.workspace
= workspace
;
367 public void setDistCoordinates(String distCoordinates
) {
368 this.distCoordinates
= distCoordinates
;
371 public void setArtifactBasePath(String artifactBasePath
) {
372 this.artifactBasePath
= artifactBasePath
;