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.aar;
020:
021: import org.apache.maven.artifact.Artifact;
022: import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
023: import org.apache.maven.plugin.AbstractMojo;
024: import org.apache.maven.plugin.MojoExecutionException;
025: import org.apache.maven.project.MavenProject;
026: import org.codehaus.plexus.util.DirectoryScanner;
027: import org.codehaus.plexus.util.FileUtils;
028:
029: import java.io.File;
030: import java.io.IOException;
031: import java.util.ArrayList;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Set;
035:
036: /** Abstract base class of all the mojos in the axis2-aar-maven-plugin. */
037: public abstract class AbstractAarMojo extends AbstractMojo {
038:
039: /**
040: * The projects base directory.
041: *
042: * @parameter expression="${project.basedir}"
043: * @required
044: * @readonly
045: */
046: protected File baseDir;
047:
048: /**
049: * The maven project.
050: *
051: * @parameter expression="${project}"
052: * @required
053: * @readonly
054: */
055: protected MavenProject project;
056:
057: /**
058: * The directory containing generated classes.
059: *
060: * @parameter expression="${project.build.outputDirectory}"
061: * @required
062: */
063: private File classesDirectory;
064:
065: /**
066: * The directory where the aar is built.
067: *
068: * @parameter expression="${project.build.directory}/aar"
069: * @required
070: */
071: protected File aarDirectory;
072:
073: /**
074: * The location of the services.xml file. If it is present in the META-INF directory in
075: * src/main/resources with that name then it will automatically be included. Otherwise this
076: * parameter must be set.
077: *
078: * @parameter
079: */
080: private File servicesXmlFile;
081:
082: /**
083: * The location of the WSDL file, if any. By default, no WSDL file is added and it is assumed,
084: * that Axis 2 will automatically generate a WSDL file.
085: *
086: * @parameter
087: */
088: private File wsdlFile;
089:
090: /**
091: * Name, to which the wsdl file shall be mapped. By default, the name will be computed from the
092: * files path by removing the directory.
093: *
094: * @parameter default-value="service.wsdl"
095: */
096: private String wsdlFileName;
097:
098: /**
099: * Additional file sets, which are being added to the archive.
100: *
101: * @parameter
102: */
103: private FileSet[] fileSets;
104:
105: /**
106: * Whether the dependency jars should be included in the aar
107: *
108: * @parameter expression="${includeDependencies}" default-value="true"
109: */
110: private boolean includeDependencies;
111:
112: /**
113: * Builds the exploded AAR file.
114: *
115: * @throws MojoExecutionException
116: */
117: protected void buildExplodedAar() throws MojoExecutionException {
118: getLog().debug("Exploding aar...");
119:
120: aarDirectory.mkdirs();
121: getLog().debug(
122: "Assembling aar " + project.getArtifactId() + " in "
123: + aarDirectory);
124:
125: try {
126: final File metaInfDir = new File(aarDirectory, "META-INF");
127: final File libDir = new File(aarDirectory, "lib");
128: final File servicesFileTarget = new File(metaInfDir,
129: "services.xml");
130: boolean existsBeforeCopyingClasses = servicesFileTarget
131: .exists();
132:
133: String wsdlName = wsdlFileName;
134: if (wsdlName == null && wsdlFile != null) {
135: wsdlName = wsdlFile.getName();
136: }
137: File wsdlFileTarget = null;
138: if (wsdlFile != null) {
139: wsdlFileTarget = new File(metaInfDir, wsdlFileName);
140: }
141: boolean wsdlExistsBeforeCopyingClasses = wsdlFileTarget == null ? false
142: : wsdlFileTarget.exists();
143:
144: if (classesDirectory.exists()
145: && (!classesDirectory.equals(aarDirectory))) {
146: FileUtils.copyDirectoryStructure(classesDirectory,
147: aarDirectory);
148: }
149:
150: if (fileSets != null) {
151: for (int i = 0; i < fileSets.length; i++) {
152: FileSet fileSet = fileSets[i];
153: copyFileSet(fileSet, aarDirectory);
154: }
155: }
156:
157: copyMetaInfFile(servicesXmlFile, servicesFileTarget,
158: existsBeforeCopyingClasses, "services.xml file");
159: copyMetaInfFile(wsdlFile, wsdlFileTarget,
160: wsdlExistsBeforeCopyingClasses, "WSDL file");
161:
162: if (includeDependencies) {
163: Set artifacts = project.getArtifacts();
164:
165: List duplicates = findDuplicates(artifacts);
166:
167: for (Iterator iter = artifacts.iterator(); iter
168: .hasNext();) {
169: Artifact artifact = (Artifact) iter.next();
170: String targetFileName = getDefaultFinalName(artifact);
171:
172: getLog().debug("Processing: " + targetFileName);
173:
174: if (duplicates.contains(targetFileName)) {
175: getLog().debug(
176: "Duplicate found: " + targetFileName);
177: targetFileName = artifact.getGroupId() + "-"
178: + targetFileName;
179: getLog().debug("Renamed to: " + targetFileName);
180: }
181:
182: // TODO: utilise appropriate methods from project builder
183: ScopeArtifactFilter filter = new ScopeArtifactFilter(
184: Artifact.SCOPE_RUNTIME);
185: if (!artifact.isOptional()
186: && filter.include(artifact)) {
187: String type = artifact.getType();
188: if ("jar".equals(type)) {
189: copyFileIfModified(artifact.getFile(),
190: new File(libDir, targetFileName));
191: }
192: }
193: }
194: }
195: } catch (IOException e) {
196: throw new MojoExecutionException(
197: "Could not explode aar...", e);
198: }
199: }
200:
201: /**
202: * Searches a set of artifacts for duplicate filenames and returns a list of duplicates.
203: *
204: * @param artifacts set of artifacts
205: * @return List of duplicated artifacts
206: */
207: private List findDuplicates(Set artifacts) {
208: List duplicates = new ArrayList();
209: List identifiers = new ArrayList();
210: for (Iterator iter = artifacts.iterator(); iter.hasNext();) {
211: Artifact artifact = (Artifact) iter.next();
212: String candidate = getDefaultFinalName(artifact);
213: if (identifiers.contains(candidate)) {
214: duplicates.add(candidate);
215: } else {
216: identifiers.add(candidate);
217: }
218: }
219: return duplicates;
220: }
221:
222: /**
223: * Converts the filename of an artifact to artifactId-version.type format.
224: *
225: * @param artifact
226: * @return converted filename of the artifact
227: */
228: private String getDefaultFinalName(Artifact artifact) {
229: return artifact.getArtifactId() + "-" + artifact.getVersion()
230: + "." + artifact.getArtifactHandler().getExtension();
231: }
232:
233: /**
234: * Copy file from source to destination only if source timestamp is later than the destination
235: * timestamp. The directories up to <code>destination</code> will be created if they don't
236: * already exist. <code>destination</code> will be overwritten if it already exists.
237: *
238: * @param source An existing non-directory <code>File</code> to copy bytes from.
239: * @param destination A non-directory <code>File</code> to write bytes to (possibly
240: * overwriting).
241: * @throws IOException if <code>source</code> does not exist,
242: * <code>destination</code> cannot be written to, or an IO
243: * error occurs during copying.
244: * @throws java.io.FileNotFoundException if <code>destination</code> is a directory
245: * <p/>
246: * TO DO: Remove this method when Maven moves to
247: * plexus-utils version 1.4
248: */
249: private void copyFileIfModified(File source, File destination)
250: throws IOException {
251: // TO DO: Remove this method and use the method in WarFileUtils when Maven 2 changes
252: // to plexus-utils 1.2.
253: if (destination.lastModified() < source.lastModified()) {
254: FileUtils.copyFile(source.getCanonicalFile(), destination);
255: // preserve timestamp
256: destination.setLastModified(source.lastModified());
257: }
258: }
259:
260: private void copyFileSet(FileSet fileSet, File targetDirectory)
261: throws IOException {
262: File dir = fileSet.getDirectory();
263: if (dir == null) {
264: dir = baseDir;
265: }
266: File targetDir = targetDirectory;
267: if (fileSet.getOutputDirectory() != null) {
268: targetDir = new File(targetDir, fileSet
269: .getOutputDirectory());
270: }
271: if (targetDir.equals(dir)) {
272: return;
273: }
274:
275: DirectoryScanner ds = new DirectoryScanner();
276: ds.setBasedir(dir);
277: if (!fileSet.isSkipDefaultExcludes()) {
278: ds.addDefaultExcludes();
279: }
280: final String[] excludes = fileSet.getExcludes();
281: if (excludes != null) {
282: ds.setExcludes(excludes);
283: }
284: final String[] includes = fileSet.getIncludes();
285: if (includes != null) {
286: ds.setIncludes(includes);
287: }
288: ds.scan();
289: String[] files = ds.getIncludedFiles();
290: for (int i = 0; i < files.length; i++) {
291: File sourceFile = new File(dir, files[i]);
292: File targetFile = new File(targetDir, files[i]);
293: FileUtils.copyFile(sourceFile, targetFile);
294: }
295: }
296:
297: private void copyMetaInfFile(final File pSource,
298: final File pTarget, final boolean pExistsBeforeCopying,
299: final String pDescription) throws MojoExecutionException,
300: IOException {
301: if (pSource != null && pTarget != null) {
302: if (!pSource.exists()) {
303: throw new MojoExecutionException("The configured "
304: + pDescription + " could not be found at "
305: + pSource);
306: }
307:
308: if (!pExistsBeforeCopying && pTarget.exists()) {
309: getLog()
310: .warn(
311: "The configured "
312: + pDescription
313: + " overwrites another file from the classpath.");
314: }
315:
316: FileUtils.copyFile(pSource, pTarget);
317: }
318: }
319: }
|