001: package org.andromda.maven.plugin.andromdapp.eclipse;
002:
003: import java.io.File;
004: import java.io.FileWriter;
005:
006: import java.util.ArrayList;
007: import java.util.Collections;
008: import java.util.Iterator;
009: import java.util.LinkedHashSet;
010: import java.util.List;
011: import java.util.ListIterator;
012: import java.util.Set;
013:
014: import org.andromda.core.common.ResourceUtils;
015: import org.apache.commons.lang.StringUtils;
016: import org.apache.maven.artifact.Artifact;
017: import org.apache.maven.artifact.factory.ArtifactFactory;
018: import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
019: import org.apache.maven.artifact.repository.ArtifactRepository;
020: import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
021: import org.apache.maven.artifact.resolver.ArtifactResolver;
022: import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
023: import org.apache.maven.plugin.logging.Log;
024: import org.apache.maven.project.MavenProject;
025: import org.codehaus.plexus.util.IOUtil;
026: import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
027: import org.codehaus.plexus.util.xml.XMLWriter;
028:
029: /**
030: * Writes the Eclipse .classpath files.
031: *
032: * @author Chad Brandon
033: */
034: public class ClasspathWriter extends EclipseWriter {
035: public ClasspathWriter(final MavenProject project, final Log logger) {
036: super (project, logger);
037: }
038:
039: /**
040: * Writes the .classpath file for eclipse.
041: *
042: * @param projects the list of projects from which the .classpath will get its dependencies.
043: * @param repositoryVariableName the name of the maven repository variable.
044: * @param artifactFactory the factory for constructing artifacts.
045: * @param artifactResolver the artifact resolver.
046: * @param localRepository the local repository instance.
047: * @param artifactMetadataSource
048: * @param classpathArtifactTypes the artifacts types that are allowed in the classpath file.
049: * @param remoteRepositories the list of remote repository instances.
050: * @param resolveTransitiveDependencies whether or not dependencies shall be transitively resolved.
051: * @param merge anything extra (not auto-generated), that should be "merged" into the generated .classpath
052: * @throws Exception
053: */
054: public void write(final List projects,
055: final String repositoryVariableName,
056: final ArtifactFactory artifactFactory,
057: final ArtifactResolver artifactResolver,
058: final ArtifactRepository localRepository,
059: final ArtifactMetadataSource artifactMetadataSource,
060: final Set classpathArtifactTypes,
061: final List remoteRepositories,
062: final boolean resolveTransitiveDependencies,
063: final String merge) throws Exception {
064: final String rootDirectory = ResourceUtils
065: .normalizePath(this .project.getBasedir().toString());
066: final File classpathFile = new File(rootDirectory, ".classpath");
067: final FileWriter fileWriter = new FileWriter(classpathFile);
068: final XMLWriter writer = new PrettyPrintXMLWriter(fileWriter);
069:
070: writer.startElement("classpath");
071:
072: final Set projectArtifactIds = new LinkedHashSet();
073: for (final Iterator iterator = projects.iterator(); iterator
074: .hasNext();) {
075: final MavenProject project = (MavenProject) iterator.next();
076: final Artifact projectArtifact = artifactFactory
077: .createArtifact(project.getGroupId(), project
078: .getArtifactId(), project.getVersion(),
079: null, project.getPackaging());
080: projectArtifactIds.add(projectArtifact.getId());
081: }
082:
083: // - write the source roots for the root project (if they are any)
084: this .writeSourceRoots(this .project, rootDirectory, writer);
085:
086: final Set allArtifacts = new LinkedHashSet(this .project
087: .createArtifacts(artifactFactory, null, null));
088: for (final Iterator iterator = projects.iterator(); iterator
089: .hasNext();) {
090: final MavenProject project = (MavenProject) iterator.next();
091: this .writeSourceRoots(project, rootDirectory, writer);
092: final Set artifacts = project.createArtifacts(
093: artifactFactory, null, null);
094:
095: // - get the direct dependencies
096: for (final Iterator artifactIterator = artifacts.iterator(); artifactIterator
097: .hasNext();) {
098: final Artifact artifact = (Artifact) artifactIterator
099: .next();
100:
101: // - don't attempt to resolve the artifact if its part of the project (we
102: // infer this if it has the same id has one of the projects or is in
103: // the same groupId).
104: if (!projectArtifactIds.contains(artifact.getId())
105: && !project.getGroupId().equals(
106: artifact.getGroupId())) {
107: artifactResolver.resolve(artifact, project
108: .getRemoteArtifactRepositories(),
109: localRepository);
110: allArtifacts.add(artifact);
111: } else {
112: allArtifacts.add(artifact);
113: }
114: }
115: }
116:
117: // - remove the project artifacts
118: for (final Iterator iterator = projects.iterator(); iterator
119: .hasNext();) {
120: final MavenProject project = (MavenProject) iterator.next();
121: final Artifact projectArtifact = project.getArtifact();
122: if (projectArtifact != null) {
123: for (final Iterator artifactIterator = allArtifacts
124: .iterator(); artifactIterator.hasNext();) {
125: final Artifact artifact = (Artifact) artifactIterator
126: .next();
127: final String projectId = projectArtifact
128: .getArtifactId();
129: final String projectGroupId = projectArtifact
130: .getGroupId();
131: final String artifactId = artifact.getArtifactId();
132: final String groupId = artifact.getGroupId();
133: if (artifactId.equals(projectId)
134: && groupId.equals(projectGroupId)) {
135: artifactIterator.remove();
136: }
137: }
138: }
139: }
140:
141: // - now we resolve transitively, if we have the flag on
142: if (resolveTransitiveDependencies) {
143: final Artifact rootProjectArtifact = artifactFactory
144: .createArtifact(this .project.getGroupId(),
145: this .project.getArtifactId(), this .project
146: .getVersion(), null, this .project
147: .getPackaging());
148:
149: final OrArtifactFilter filter = new OrArtifactFilter();
150: filter.add(new ScopeArtifactFilter(Artifact.SCOPE_COMPILE));
151: filter
152: .add(new ScopeArtifactFilter(
153: Artifact.SCOPE_PROVIDED));
154: final ArtifactResolutionResult result = artifactResolver
155: .resolveTransitively(allArtifacts,
156: rootProjectArtifact, localRepository,
157: remoteRepositories, artifactMetadataSource,
158: filter);
159:
160: allArtifacts.clear();
161: allArtifacts.addAll(result.getArtifacts());
162: }
163:
164: final List allArtifactPaths = new ArrayList(allArtifacts);
165: for (final ListIterator iterator = allArtifactPaths
166: .listIterator(); iterator.hasNext();) {
167: final Artifact artifact = (Artifact) iterator.next();
168: if (classpathArtifactTypes.contains(artifact.getType())) {
169: final File artifactFile = artifact.getFile();
170: final String path = StringUtils.replace(ResourceUtils
171: .normalizePath(artifactFile.toString()),
172: ResourceUtils.normalizePath(localRepository
173: .getBasedir()), repositoryVariableName);
174: iterator.set(path);
175: } else {
176: iterator.remove();
177: }
178: }
179:
180: // - sort the paths
181: Collections.sort(allArtifactPaths);
182:
183: for (final Iterator iterator = allArtifactPaths.iterator(); iterator
184: .hasNext();) {
185: final String path = (String) iterator.next();
186: if (path.startsWith(repositoryVariableName)) {
187: this .writeClasspathEntry(writer, "var", path);
188: } else {
189: this .writeClasspathEntry(writer, "lib", path);
190: }
191: }
192:
193: this .writeClasspathEntry(writer, "con",
194: "org.eclipse.jdt.launching.JRE_CONTAINER");
195:
196: String outputPath = StringUtils.replace(ResourceUtils
197: .normalizePath(this .project.getBuild()
198: .getOutputDirectory()), rootDirectory, "");
199: if (outputPath.startsWith("/")) {
200: outputPath = outputPath.substring(1, outputPath.length());
201: }
202: this .writeClasspathEntry(writer, "output", outputPath);
203:
204: if (StringUtils.isNotBlank(merge)) {
205: writer.writeMarkup(merge);
206: }
207: writer.endElement();
208:
209: logger.info("Classpath file written --> '" + classpathFile
210: + "'");
211: IOUtil.close(fileWriter);
212: }
213:
214: /**
215: * Writes the source roots for the given project.
216: *
217: * @param project the project for which to write the source roots.
218: * @param rootDirectory the root project's base directory
219: * @param writer the XMLWriter used to write the source roots.
220: */
221: private void writeSourceRoots(final MavenProject project,
222: final String rootDirectory, final XMLWriter writer) {
223: for (final Iterator sourceIterator = project
224: .getCompileSourceRoots().iterator(); sourceIterator
225: .hasNext();) {
226: final String sourceRoot = ResourceUtils
227: .normalizePath((String) sourceIterator.next());
228: if (new File(sourceRoot).isDirectory()) {
229: String sourceRootPath = StringUtils.replace(sourceRoot,
230: rootDirectory, "");
231: if (sourceRootPath.startsWith("/")) {
232: sourceRootPath = sourceRootPath.substring(1,
233: sourceRootPath.length());
234: this .writeClasspathEntry(writer, "src",
235: sourceRootPath);
236: }
237: }
238: }
239: }
240:
241: /**
242: * Writes a classpathentry with the given <code>kind</code> and <code>path</code> values.
243: *
244: * @param writer the XML writer with which to write.
245: * @param kind the kind of the classpath entry.
246: * @param path the path of the classpath entry.
247: */
248: private void writeClasspathEntry(final XMLWriter writer,
249: final String kind, final String path) {
250: writer.startElement("classpathentry");
251: writer.addAttribute("kind", kind);
252: writer.addAttribute("path", path);
253: writer.endElement();
254: }
255: }
|