KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > sourcecontrols > Maven2SnapshotDependency


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2001, ThoughtWorks, Inc.
4  * 651 W Washington Ave. Suite 600
5  * Chicago, IL 60661 USA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * + Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * + Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
21  * names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior
23  * written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  ********************************************************************************/

37 package net.sourceforge.cruisecontrol.sourcecontrols;
38
39 import org.apache.log4j.Logger;
40 import org.apache.maven.embedder.MavenEmbedder;
41 import org.apache.maven.embedder.MavenEmbedderConsoleLogger;
42 import org.apache.maven.embedder.MavenEmbedderException;
43 import org.apache.maven.model.Dependency;
44 import org.apache.maven.model.Model;
45 import org.apache.maven.project.MavenProject;
46 import org.apache.maven.project.ProjectBuildingException;
47 import org.apache.maven.artifact.repository.ArtifactRepository;
48 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
49 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
50 import org.apache.maven.artifact.Artifact;
51 import org.apache.maven.cli.ConsoleDownloadMonitor;
52 import org.apache.maven.wagon.events.TransferEvent;
53 import org.apache.maven.wagon.events.TransferListener;
54 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
55
56 import java.util.ArrayList JavaDoc;
57 import java.util.Date JavaDoc;
58 import java.util.List JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.Map JavaDoc;
61 import java.util.HashMap JavaDoc;
62 import java.util.Set JavaDoc;
63 import java.util.HashSet JavaDoc;
64 import java.io.File JavaDoc;
65
66 import net.sourceforge.cruisecontrol.CruiseControlException;
67 import net.sourceforge.cruisecontrol.SourceControl;
68 import net.sourceforge.cruisecontrol.Modification;
69 import net.sourceforge.cruisecontrol.util.ValidationHelper;
70
71 /**
72  * Checks snapshot dependencies listed in a Maven2 pom against the local repositorty.
73  *
74  * Date: Feb 8, 2006
75  * Time: 9:15:47 PM
76  *
77  * @author Dan Rollo
78  */

79 public class Maven2SnapshotDependency implements SourceControl {
80
81     /** enable logging for this class */
82     private static final Logger LOG = Logger.getLogger(Maven2SnapshotDependency.class);
83
84     private final Map JavaDoc properties = new HashMap JavaDoc();
85     private String JavaDoc property;
86     private List JavaDoc modifications;
87     private File JavaDoc pomFile;
88     private String JavaDoc user;
89     private File JavaDoc localRepoDir; //@todo Must be null until maven embedder honors alignWithUserInstallation.
90

91     static final String JavaDoc COMMENT_TIMESTAMP_CHANGE = " timestamp change detected: ";
92     static final String JavaDoc COMMENT_MISSING_IN_LOCALREPO = " missing in local repo: ";
93
94
95     /**
96      * Set the root folder of the directories that we are going to scan
97      */

98     public void setPomFile(String JavaDoc s) {
99         pomFile = new File JavaDoc(s);
100     }
101
102     /**
103      * Set the path for the local Maven repository.
104      * Normally, this is not set in order to use the default location: user.home/.m2/repository.
105      */

106     //@todo Make "public" when maven embedder honors alignWithUserInstallation
107
void setLocalRepository(String JavaDoc s) throws CruiseControlException {
108         if (s != null) {
109             localRepoDir = new File JavaDoc(s);
110         } else {
111             localRepoDir = null;
112         }
113     }
114
115     /**
116      * Set the username listed with changes found in binary dependencies
117      */

118     public void setUser(String JavaDoc s) {
119         user = s;
120     }
121
122     public void setProperty(String JavaDoc property) {
123         this.property = property;
124     }
125
126     public Map JavaDoc getProperties() {
127         return properties;
128     }
129
130
131     public void validate() throws CruiseControlException {
132
133         ValidationHelper.assertIsSet(pomFile, "pomFile", this.getClass());
134
135         ValidationHelper.assertTrue(pomFile.exists(),
136             "Pom file '" + pomFile.getAbsolutePath() + "' does not exist.");
137
138         ValidationHelper.assertFalse(pomFile.isDirectory(),
139             "The directory '" + pomFile.getAbsolutePath()
140             + "' cannot be used as the pomFile for Maven2SnapshotDependency.");
141
142
143         if (localRepoDir != null) {
144             ValidationHelper.assertTrue(localRepoDir.exists(),
145                 "Local Maven repository '" + localRepoDir.getAbsolutePath() + "' does not exist.");
146
147             ValidationHelper.assertTrue(localRepoDir.isDirectory(),
148                 "Local Maven repository '" + localRepoDir.getAbsolutePath()
149                 + "' must be a directory.");
150         }
151     }
152
153
154     /**
155      * The quiet period is ignored. All dependencies changed since the last
156      * build trigger a modification.
157      *
158      * <at> param lastBuild
159      * date of last build
160      * <at> param now
161      * IGNORED
162      */

163     public List JavaDoc getModifications(Date JavaDoc lastBuild, Date JavaDoc now) {
164
165         modifications = new ArrayList JavaDoc();
166
167         LOG.debug("Reading pom: " + pomFile.getAbsolutePath() + " with lastBuild: " + lastBuild);
168
169         ArtifactInfo[] artifactsToCheck = getSnapshotInfos();
170
171         for (int i = 0; i < artifactsToCheck.length; i++) {
172             checkFile(artifactsToCheck[i], lastBuild.getTime());
173         }
174
175         return modifications;
176     }
177
178
179     /**
180      * Add a Modification to the list of modifications. All modifications are
181      * listed as "change" or "missing" if not in local repo.
182      */

183     private void addRevision(File JavaDoc dependency, String JavaDoc changeType, String JavaDoc comment) {
184         Modification newMod = new Modification("maven2");
185         Modification.ModifiedFile modfile = newMod.createModifiedFile(dependency.getName(), dependency.getParent());
186         modfile.action = changeType;
187
188         newMod.userName = user;
189         newMod.modifiedTime = new Date JavaDoc(dependency.lastModified());
190         newMod.comment = comment;
191         modifications.add(newMod);
192
193         if (property != null) {
194             properties.put(property, "true");
195         }
196     }
197
198
199     /** Immutable data holder class. */
200     static final class ArtifactInfo {
201         static final String JavaDoc ART_TYPE_PARENT = "parent";
202         static final String JavaDoc ART_TYPE_DEPENDENCY = "dependency";
203
204         private final Artifact artifact;
205         private final String JavaDoc artifactType;
206         private final File JavaDoc localRepoFile;
207
208         private ArtifactInfo(final Artifact artifact, final String JavaDoc artifactType, File JavaDoc localRepoFile) {
209             this.artifact = artifact;
210             this.artifactType = artifactType;
211             this.localRepoFile = localRepoFile;
212         }
213
214         Artifact getArtifact() {
215             return artifact;
216         }
217
218         String JavaDoc getArtifactType() {
219             return artifactType;
220         }
221
222         File JavaDoc getLocalRepoFile() {
223             return localRepoFile;
224         }
225
226         public String JavaDoc toString() {
227             return artifact + "," + artifactType + ","
228                     + (localRepoFile != null ? localRepoFile.getAbsolutePath() : null);
229         }
230     }
231
232
233     /**
234      * Return a file referring to the given artifact in the local reprository.
235      * @param localRepoBaseDir the actual base dir of the active local reprository
236      * @param artifact a artifact to be checked in the local reprository
237      * @return a file referring to the given artifact in the local reprository
238      */

239     //@todo Maybe we can delete this whole method after a while.
240
private static File JavaDoc getArtifactFilename(final File JavaDoc localRepoBaseDir, final Artifact artifact) {
241
242         LOG.warn("We should not need this approach to finding artifact files. Artifact: " + artifact);
243
244         // Format:
245
// ${repo}/${groupId,dots as dirs}/${artifactId}/${version}/${artifactId}-${version}[-${classifier}].${type}
246
StringBuffer JavaDoc fileName = new StringBuffer JavaDoc();
247         fileName.append(localRepoBaseDir.getAbsolutePath());
248
249         fileName.append('/');
250
251         fileName.append(artifact.getGroupId().replace('.', '/'));
252
253         fileName.append('/');
254
255         final String JavaDoc artifactId = artifact.getArtifactId();
256         fileName.append(artifactId);
257
258         fileName.append('/');
259
260         final String JavaDoc versionText = artifact.getVersion();
261         fileName.append(versionText);
262
263         fileName.append('/');
264
265         fileName.append(artifactId);
266         fileName.append('-');
267         fileName.append(versionText);
268
269         if (artifact.getClassifier() != null) {
270             fileName.append('-');
271             fileName.append(artifact.getClassifier());
272         }
273
274         fileName.append('.');
275
276         final String JavaDoc type = artifact.getType();
277         fileName.append(type != null ? type : "jar");
278
279         //@todo Handle type="system" and "systemPath", or not if we can delete this whole method.
280

281         return new File JavaDoc(fileName.toString());
282     }
283
284     /**
285      * Parse the Maven pom file, and return snapshot artifact info populated with dependencies to be checked
286      */

287     ArtifactInfo[] getSnapshotInfos() {
288
289         final MavenEmbedder embedder = getMvnEmbedder();
290         try {
291
292             // With readProjectWithDependencies(), local repo dependencies (+transitive) will be updated if possible
293
final MavenProject projectWithDependencies = getProjectWithDependencies(embedder, pomFile);
294
295             // use local repo dir from embedder because this is the dir it is actually using
296
final File JavaDoc localRepoBaseDir = new File JavaDoc(embedder.getLocalRepository().getBasedir());
297
298
299             final List JavaDoc artifactInfos = new ArrayList JavaDoc();
300
301             // handle parents and grandparents...
302
findParentSnapshotArtifacts(projectWithDependencies, artifactInfos, localRepoBaseDir, embedder, pomFile);
303
304
305             // handle dependencies
306
final Set JavaDoc snapshotArtifacts;
307             if (projectWithDependencies != null) {
308
309                 // projectWithDependencies.getDependencyArtifacts() would exclude transitive artifacts
310
snapshotArtifacts = getSnaphotArtifacts(projectWithDependencies.getArtifacts());
311
312             } else {
313
314                 // couldn't read project, so try to do some stuff manually
315
snapshotArtifacts = getSnapshotArtifactsManually(embedder);
316             }
317             Artifact artifact;
318             for (Iterator JavaDoc i = snapshotArtifacts.iterator(); i.hasNext(); ) {
319                 artifact = (Artifact) i.next();
320
321                 addArtifactInfo(artifactInfos, artifact, ArtifactInfo.ART_TYPE_DEPENDENCY, localRepoBaseDir);
322             }
323
324
325             return (ArtifactInfo[]) artifactInfos.toArray(new ArtifactInfo[]{});
326
327         } finally {
328             try {
329                 embedder.stop();
330             } catch (MavenEmbedderException e) {
331                 LOG.error("Failed to stop embedded maven2", e);
332             }
333         }
334     }
335
336     private static void findParentSnapshotArtifacts(MavenProject projectWithDependencies, List JavaDoc artifactInfos,
337                                                     File JavaDoc localRepoBaseDir, MavenEmbedder embedder, File JavaDoc pomFile) {
338         // handle parents and grandparents...
339
if (projectWithDependencies != null) {
340
341             Artifact parentArtifact;
342             MavenProject currMvnProject = projectWithDependencies;
343
344             while ((parentArtifact = currMvnProject.getParentArtifact()) != null
345                     && parentArtifact.isSnapshot()) {
346
347                 addArtifactInfo(artifactInfos, parentArtifact, ArtifactInfo.ART_TYPE_PARENT, localRepoBaseDir);
348                 currMvnProject = projectWithDependencies.getParent();
349             }
350
351         } else {
352
353             // couldn't read project, so try to do some stuff manually
354
MavenProject mavenProject = null;
355             try {
356                 mavenProject = embedder.readProject(pomFile);
357             } catch (ProjectBuildingException e) {
358                 LOG.error("Failed to read maven2 mavenProject", e);
359             }
360
361             if (mavenProject != null) {
362
363                 Artifact artifact;
364                 MavenProject currMvnProject = mavenProject;
365
366                 while ((artifact = currMvnProject.getParentArtifact()) != null
367                         && (artifact.getVersion().endsWith(Artifact.SNAPSHOT_VERSION) || artifact.isSnapshot())
368                         ) {
369
370                     addArtifactInfo(artifactInfos, artifact, ArtifactInfo.ART_TYPE_PARENT, localRepoBaseDir);
371
372                     resolveArtifact(embedder, artifact, mavenProject, embedder.getLocalRepository());
373
374                     currMvnProject = mavenProject.getParent();
375                 }
376             }
377         }
378     }
379
380     private static MavenProject getProjectWithDependencies(MavenEmbedder embedder, File JavaDoc pomFile) {
381         // With readProjectWithDependencies(), local repo dependencies (+transitive) will be updated if possible
382
MavenProject projectWithDependencies = null;
383         try {
384
385             final TransferListener transferListener = new ConsoleDownloadMonitor() {
386                 public void transferProgress(TransferEvent transferEvent, byte[] buffer, int length) {
387                     // do nothing to avoid lot's of progress messages in logs
388
}
389             };
390
391             projectWithDependencies = embedder.readProjectWithDependencies(pomFile, transferListener);
392
393         } catch (ProjectBuildingException e) {
394             LOG.error("Failed to read maven2 projectWithDependencies", e);
395         } catch (ArtifactResolutionException e) {
396             LOG.warn("Failed to resolve artifact", e);
397         } catch (ArtifactNotFoundException e) {
398             LOG.warn("Couldn't find artifact", e);
399         }
400         return projectWithDependencies;
401     }
402
403     private static void resolveArtifact(MavenEmbedder embedder, Artifact artifact,
404                                         MavenProject mavenProject, ArtifactRepository localRepo) {
405         try {
406             embedder.resolve(artifact, mavenProject.getPluginArtifactRepositories(), localRepo);
407         } catch (ArtifactResolutionException e) {
408             LOG.debug("Unresolved artifact", e);
409         } catch (ArtifactNotFoundException e) {
410             LOG.debug("Missing artifact", e);
411         }
412     }
413
414
415     private static void addArtifactInfo(List JavaDoc artifactInfos, Artifact artifact, String JavaDoc artifactType,
416                                         File JavaDoc localRepoBaseDir) {
417
418         final File JavaDoc file;
419         if (artifact.getFile() == null) {
420             file = getArtifactFilename(localRepoBaseDir, artifact);
421         } else {
422             file = artifact.getFile();
423         }
424
425         artifactInfos.add(new ArtifactInfo(artifact, artifactType, file));
426     }
427
428
429     /** Filter out non-SNAPSHOT artifacts. */
430     private static Set JavaDoc getSnaphotArtifacts(final Set JavaDoc artifacts) {
431
432         final Set JavaDoc retVal = new HashSet JavaDoc();
433
434         Artifact artifact;
435         for (Iterator JavaDoc i = artifacts.iterator(); i.hasNext(); ) {
436             artifact = (Artifact) i.next();
437             LOG.debug("Examining artifact: " + artifact);
438             if (artifact.isSnapshot()) {
439                 retVal.add(artifact);
440             }
441         }
442
443         return retVal;
444     }
445
446
447     /** Doesn't handle transitive deps, nor actually download anything so far */
448     private Set JavaDoc getSnapshotArtifactsManually(final MavenEmbedder embedder) {
449
450         final MavenProject mavenProject;
451         try {
452             mavenProject = embedder.readProject(pomFile);
453         } catch (ProjectBuildingException e) {
454             LOG.error("Failed to read maven2 mavenProject", e);
455             return new HashSet JavaDoc();
456         }
457
458         // override default repo if needed
459
final ArtifactRepository localRepo;
460         if (localRepoDir != null) {
461             try {
462                 localRepo = embedder.createLocalRepository(localRepoDir);
463             } catch (ComponentLookupException e) {
464                 LOG.error("Error setting maven2 local repo to: " + localRepoDir.getAbsolutePath(), e);
465                 throw new RuntimeException JavaDoc("Error setting maven2 local repo to: " + localRepoDir.getAbsolutePath()
466                         + "; " + e.getMessage());
467             }
468         } else {
469             localRepo = embedder.getLocalRepository();
470         }
471
472         // get snapshot dependencies
473
final Set JavaDoc snapshotArtifacts = getSnapshotDepsManually(embedder, mavenProject);
474
475         Artifact artifact;
476         for (Iterator JavaDoc i = snapshotArtifacts.iterator(); i.hasNext();) {
477             artifact = (Artifact) i.next();
478             LOG.debug("Manually examining artifact: " + artifact);
479             resolveArtifact(embedder, artifact, mavenProject, localRepo);
480         }
481
482         return snapshotArtifacts;
483     }
484
485     private static Set JavaDoc getSnapshotDepsManually(final MavenEmbedder mavenEmbedder, final MavenProject mavenProject) {
486         final Set JavaDoc retVal = new HashSet JavaDoc();
487
488         // Not really sure if mavenEmbedder.readProject() is any better than mavenEmbedder.readModel()
489
// At this point, which ever is used, it should not update files in the local repo.
490

491         /*
492         //final Set deps = mavenProject.getDependencyArtifacts(); // This returns null, how to init embedder correctly?
493         final List depsList = mavenProject.getDependencyManagement().getSnapshotDepsManually();
494         //*/

495
496         //* // should not update files in the local repo.
497
final Model model = mavenProject.getModel();
498         final List JavaDoc depsList = model.getDependencies();
499         //*/
500

501
502         LOG.debug("found dependencies manually: " + depsList.toString());
503         Dependency dep;
504         Artifact artifact;
505         for (int i = 0; i < depsList.size(); i++) {
506             dep = (Dependency) depsList.get(i);
507             if (dep.getVersion().endsWith(Artifact.SNAPSHOT_VERSION)) {
508                 if (dep.getClassifier() != null) {
509                     artifact = mavenEmbedder.createArtifactWithClassifier(dep.getGroupId(), dep.getArtifactId(),
510                                     dep.getVersion(), dep.getType(), dep.getClassifier());
511                 } else {
512                     artifact = mavenEmbedder.createArtifact(dep.getGroupId(), dep.getArtifactId(), dep.getVersion(),
513                                     dep.getScope(), dep.getType());
514                 }
515
516                 if (Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
517                     // fill in systemPath for file
518
artifact.setFile(new File JavaDoc(dep.getSystemPath(),
519                             artifact.getArtifactId() + "-" + artifact.getVersion()
520                                     + (artifact.getClassifier() != null ? "-" + artifact.getClassifier() : "")
521                                     + "." + artifact.getType()));
522                 }
523                 retVal.add(artifact);
524             }
525         }
526
527         return retVal;
528     }
529
530
531     /** Check for newer timestamps */
532     private void checkFile(final ArtifactInfo artifactInfo, long lastBuild) {
533         final File JavaDoc file = artifactInfo.localRepoFile;
534         LOG.debug("Checking artifact: " + artifactInfo.getArtifact());
535         if ((!file.isDirectory()) && (file.lastModified() > lastBuild)) {
536
537             addRevision(file, "change", artifactInfo.artifactType
538                     + COMMENT_TIMESTAMP_CHANGE + artifactInfo.getArtifact().getArtifactId());
539
540         } else if (!file.isDirectory() && !file.exists()) {
541
542             addRevision(file, "missing", artifactInfo.artifactType
543                     + COMMENT_MISSING_IN_LOCALREPO + artifactInfo.getArtifact().getArtifactId());
544         }
545     }
546
547     private MavenEmbedder getMvnEmbedder() {
548
549         final MavenEmbedder mvnEmbedder = new MavenEmbedder();
550         final ClassLoader JavaDoc classLoader = Thread.currentThread().getContextClassLoader();
551         mvnEmbedder.setClassLoader(classLoader);
552         mvnEmbedder.setLogger(new MavenEmbedderConsoleLogger());
553
554         // what do these really do?
555
//mvnEmbedder.setOffline(true);
556
//mvnEmbedder.setCheckLatestPluginVersion(false);
557
//mvnEmbedder.setUpdateSnapshots(false);
558
//mvnEmbedder.setInteractiveMode(false);
559
//mvnEmbedder.setUsePluginRegistry(false);
560
//mvnEmbedder.setPluginUpdateOverride(true);
561

562         if (localRepoDir != null) {
563             mvnEmbedder.setLocalRepositoryDirectory(localRepoDir);
564             mvnEmbedder.setAlignWithUserInstallation(false);
565         } else {
566             mvnEmbedder.setAlignWithUserInstallation(true);
567         }
568
569         try {
570             // embedder start can take a long time when debugging
571
mvnEmbedder.start();
572         } catch (MavenEmbedderException e) {
573             LOG.error("Failed to start embedded maven2", e);
574         }
575
576         return mvnEmbedder;
577     }
578 }
579
Popular Tags