001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.maven2.mar;
020:
021: import java.io.File;
022: import java.io.IOException;
023: import java.util.ArrayList;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Set;
027:
028: import org.apache.maven.artifact.Artifact;
029: import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
030: import org.apache.maven.plugin.AbstractMojo;
031: import org.apache.maven.plugin.MojoExecutionException;
032: import org.apache.maven.project.MavenProject;
033: import org.codehaus.plexus.util.DirectoryScanner;
034: import org.codehaus.plexus.util.FileUtils;
035:
036: /**
037: * Abstract base class of all the mojos in the axis2-mar-maven-plugin.
038: */
039: public abstract class AbstractMarMojo extends AbstractMojo {
040:
041: /**
042: * The projects base directory.
043: *
044: * @parameter expression="${project.basedir}"
045: * @required
046: * @readonly
047: */
048: protected File baseDir;
049:
050: /**
051: * The maven project.
052: *
053: * @parameter expression="${project}"
054: * @required
055: * @readonly
056: */
057: protected MavenProject project;
058:
059: /**
060: * The directory containing generated classes.
061: *
062: * @parameter expression="${project.build.outputDirectory}"
063: * @required
064: */
065: private File classesDirectory;
066:
067: /**
068: * The directory where the mar is built.
069: *
070: * @parameter expression="${project.build.directory}/mar"
071: * @required
072: */
073: protected File marDirectory;
074:
075: /**
076: * The location of the module.xml file. If it is present in the META-INF
077: * directory in src/main/resources with that name then it will automatically be
078: * included. Otherwise this parameter must be set.
079: *
080: * @parameter
081: */
082: private File moduleXmlFile;
083:
084: /**
085: * Additional file sets, which are being added to the archive.
086: *
087: * @parameter
088: */
089: private FileSet[] fileSets;
090:
091: /**
092: * Whether the dependency jars should be included in the mar
093: *
094: * @parameter expression="${includeDependencies}" default-value="true"
095: */
096: private boolean includeDependencies;
097:
098: /**
099: * Builds the exploded mar file.
100: * @throws MojoExecutionException
101: */
102: protected void buildExplodedMar() throws MojoExecutionException {
103: getLog().debug("Exploding mar...");
104:
105: marDirectory.mkdirs();
106: getLog().debug(
107: "Assembling mar " + project.getArtifactId() + " in "
108: + marDirectory);
109:
110: try {
111: final File metaInfDir = new File(marDirectory, "META-INF");
112: final File libDir = new File(marDirectory, "lib");
113: final File moduleFileTarget = new File(metaInfDir,
114: "module.xml");
115: boolean existsBeforeCopyingClasses = moduleFileTarget
116: .exists();
117:
118: if (classesDirectory.exists()
119: && (!classesDirectory.equals(marDirectory))) {
120: FileUtils.copyDirectoryStructure(classesDirectory,
121: marDirectory);
122: }
123:
124: if (fileSets != null) {
125: for (int i = 0; i < fileSets.length; i++) {
126: FileSet fileSet = fileSets[i];
127: copyFileSet(fileSet, marDirectory);
128: }
129: }
130:
131: copyMetaInfFile(moduleXmlFile, moduleFileTarget,
132: existsBeforeCopyingClasses, "module.xml file");
133:
134: if (includeDependencies) {
135: Set artifacts = project.getArtifacts();
136:
137: List duplicates = findDuplicates(artifacts);
138:
139: for (Iterator iter = artifacts.iterator(); iter
140: .hasNext();) {
141: Artifact artifact = (Artifact) iter.next();
142: String targetFileName = getDefaultFinalName(artifact);
143:
144: getLog().debug("Processing: " + targetFileName);
145:
146: if (duplicates.contains(targetFileName)) {
147: getLog().debug(
148: "Duplicate found: " + targetFileName);
149: targetFileName = artifact.getGroupId() + "-"
150: + targetFileName;
151: getLog().debug("Renamed to: " + targetFileName);
152: }
153:
154: // TODO: utilise appropriate methods from project builder
155: ScopeArtifactFilter filter = new ScopeArtifactFilter(
156: Artifact.SCOPE_RUNTIME);
157: if (!artifact.isOptional()
158: && filter.include(artifact)) {
159: String type = artifact.getType();
160: if ("jar".equals(type)) {
161: copyFileIfModified(artifact.getFile(),
162: new File(libDir, targetFileName));
163: }
164: }
165: }
166: }
167: } catch (IOException e) {
168: throw new MojoExecutionException(
169: "Could not explode mar...", e);
170: }
171: }
172:
173: /**
174: * Searches a set of artifacts for duplicate filenames and returns a list of duplicates.
175: *
176: * @param artifacts set of artifacts
177: * @return List of duplicated artifacts
178: */
179: private List findDuplicates(Set artifacts) {
180: List duplicates = new ArrayList();
181: List identifiers = new ArrayList();
182: for (Iterator iter = artifacts.iterator(); iter.hasNext();) {
183: Artifact artifact = (Artifact) iter.next();
184: String candidate = getDefaultFinalName(artifact);
185: if (identifiers.contains(candidate)) {
186: duplicates.add(candidate);
187: } else {
188: identifiers.add(candidate);
189: }
190: }
191: return duplicates;
192: }
193:
194: /**
195: * Converts the filename of an artifact to artifactId-version.type format.
196: *
197: * @param artifact
198: * @return converted filename of the artifact
199: */
200: private String getDefaultFinalName(Artifact artifact) {
201: return artifact.getArtifactId() + "-" + artifact.getVersion()
202: + "." + artifact.getArtifactHandler().getExtension();
203: }
204:
205: /**
206: * Copy file from source to destination only if source timestamp is later than the destination timestamp.
207: * The directories up to <code>destination</code> will be created if they don't already exist.
208: * <code>destination</code> will be overwritten if it already exists.
209: *
210: * @param source An existing non-directory <code>File</code> to copy bytes from.
211: * @param destination A non-directory <code>File</code> to write bytes to (possibly
212: * overwriting).
213: * @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot be
214: * written to, or an IO error occurs during copying.
215: * @throws java.io.FileNotFoundException if <code>destination</code> is a directory
216: * <p/>
217: * TO DO: Remove this method when Maven moves to plexus-utils version 1.4
218: */
219: private void copyFileIfModified(File source, File destination)
220: throws IOException {
221: // TO DO: Remove this method and use the method in WarFileUtils when Maven 2 changes
222: // to plexus-utils 1.2.
223: if (destination.lastModified() < source.lastModified()) {
224: FileUtils.copyFile(source.getCanonicalFile(), destination);
225: // preserve timestamp
226: destination.setLastModified(source.lastModified());
227: }
228: }
229:
230: private void copyFileSet(FileSet fileSet, File targetDirectory)
231: throws IOException {
232: File dir = fileSet.getDirectory();
233: if (dir == null) {
234: dir = baseDir;
235: }
236: File targetDir = targetDirectory;
237: if (fileSet.getOutputDirectory() != null) {
238: targetDir = new File(targetDir, fileSet
239: .getOutputDirectory());
240: }
241: if (targetDir.equals(dir)) {
242: return;
243: }
244:
245: DirectoryScanner ds = new DirectoryScanner();
246: ds.setBasedir(dir);
247: if (!fileSet.isSkipDefaultExcludes()) {
248: ds.addDefaultExcludes();
249: }
250: final String[] excludes = fileSet.getExcludes();
251: if (excludes != null) {
252: ds.setExcludes(excludes);
253: }
254: final String[] includes = fileSet.getIncludes();
255: if (includes != null) {
256: ds.setIncludes(includes);
257: }
258: ds.scan();
259: String[] files = ds.getIncludedFiles();
260: for (int i = 0; i < files.length; i++) {
261: File sourceFile = new File(dir, files[i]);
262: File targetFile = new File(targetDir, files[i]);
263: FileUtils.copyFile(sourceFile, targetFile);
264: }
265: }
266:
267: private void copyMetaInfFile(final File pSource,
268: final File pTarget, final boolean pExistsBeforeCopying,
269: final String pDescription) throws MojoExecutionException,
270: IOException {
271: if (pSource != null && pTarget != null) {
272: if (!pSource.exists()) {
273: throw new MojoExecutionException("The configured "
274: + pDescription + " could not be found at "
275: + pSource);
276: }
277:
278: if (!pExistsBeforeCopying && pTarget.exists()) {
279: getLog()
280: .warn(
281: "The configured "
282: + pDescription
283: + " overwrites another file from the classpath.");
284: }
285:
286: FileUtils.copyFile(pSource, pTarget);
287: }
288: }
289: }
|