
org.arakhne.maven.AbstractArakhneMojo Maven / Gradle / Ivy
/*
* $Id: org/arakhne/maven/AbstractArakhneMojo.java v12.0 2015-04-09 01:25:33$
*
* Copyright (C) 2010-12 Stephane GALLAND This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* This program is free software; you can redistribute it and/or modify
*/
package org.arakhne.maven;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.EventListener;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Contributor;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Developer;
import org.apache.maven.model.License;
import org.apache.maven.model.Model;
import org.apache.maven.model.Organization;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.Scm;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.sonatype.plexus.build.incremental.BuildContext;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNInfo;
import org.tmatesoft.svn.core.wc.SVNRevision;
/**
* Abstract implementation for all Arakhnê maven modules. This implementation is thread safe.
*
* @author Stéphane GALLAND
* @version 12.0 2015-04-09 01:25:33
* @mavengroupid org.arakhne.afc.maven
* @mavenartifactid maventools
*
* @component
*/
public abstract class AbstractArakhneMojo extends AbstractMojo {
/** Replies the preferred URL for the given contributor.
*
* @param contributor
* @param log
* @return the URL or null
if no URL could be built.
*/
protected static URL getContributorURL(Contributor contributor, Log log) {
URL url = null;
if (contributor!=null) {
String s = contributor.getUrl();
if (s!=null && !EMPTY_STRING.equals(s)) {
try {
url = new URL(s);
}
catch(Throwable _) {
url = null;
}
}
if (url==null) {
s = contributor.getEmail();
if (s!=null && !EMPTY_STRING.equals(s)) {
try {
url = new URL("mailto:"+s); //$NON-NLS-1$
}
catch(Throwable _) {
url = null;
}
}
}
}
return url;
}
/**
* Empty string constant.
*/
public static final String EMPTY_STRING = ExtendedArtifact.EMPTY_STRING;
/**
* Maven tag for artifcat id
*/
public static final String PROP_ARTIFACTID = "artifactId"; //$NON-NLS-1$
/**
* Maven tag for goup id
*/
public static final String PROP_GROUPID = "groupId"; //$NON-NLS-1$
/**
* Maven tag for version description
*/
public static final String PROP_VERSION = "version"; //$NON-NLS-1$
/**
* Preferred charset for the new MacOS and Linux operating systems.
*/
public static final String PREFERRED_CHARSET_UNIX = "UTF-8"; //$NON-NLS-1$
/**
* Preferred charset for the Windows operating systems.
*/
public static final String PREFERRED_CHARSET_WINDOWS = "windows-1250"; //$NON-NLS-1$
/**
* Preferred charset for the old MacOS operating systems.
*/
public static final String PREFERRED_CHARSET_MACOS = "MacRoman"; //$NON-NLS-1$
/**
* Preferred charset for the Java virtual machine (internal charset).
*/
public static final String PREFERRED_CHARSET_JVM = "UTF-16"; //$NON-NLS-1$
/**
* Copy a directory.
*
* @param in
* @param out
* @param skipHiddenFiles indicates if the hidden files should be ignored.
* @throws IOException
* @since 3.3
*/
public final void dirCopy(File in, File out, boolean skipHiddenFiles) throws IOException {
assert (in != null);
assert (out != null);
getLog().debug(in.toString()+"->"+out.toString()); //$NON-NLS-1$
getLog().debug("Ignore hidden files: "+skipHiddenFiles); //$NON-NLS-1$
out.mkdirs();
LinkedList candidates = new LinkedList();
candidates.add(in);
File f, targetFile;
File[] children;
while (!candidates.isEmpty()) {
f = candidates.removeFirst();
getLog().debug("Scanning: "+f); //$NON-NLS-1$
if (f.isDirectory()) {
children = f.listFiles();
if (children!=null && children.length>0) {
// Non empty directory
for(File c : children) {
if (!skipHiddenFiles || !c.isHidden()) {
getLog().debug("Discovering: "+c); //$NON-NLS-1$
candidates.add(c);
}
}
}
}
else {
// not a directory
targetFile = toOutput(in, f, out);
targetFile.getParentFile().mkdirs();
fileCopy(f, targetFile);
}
}
}
private static File toOutput(File root, File file, File newRoot) {
String filename = file.getAbsolutePath();
String rootPath = root.getAbsolutePath();
return new File(filename.replaceAll("^\\Q"+rootPath+"\\E", newRoot.getAbsolutePath())); //$NON-NLS-1$//$NON-NLS-2$
}
/**
* Delete a directory and its content.
*
* @param dir
* @throws IOException
* @since 3.3
*/
public final void dirRemove(File dir) throws IOException {
if (dir!=null) {
getLog().debug("Deleting tree: "+dir.toString()); //$NON-NLS-1$
LinkedList candidates = new LinkedList();
candidates.add(dir);
File f;
File[] children;
BuildContext buildContext = getBuildContext();
while (!candidates.isEmpty()) {
f = candidates.getFirst();
getLog().debug("Scanning: "+f); //$NON-NLS-1$
if (f.isDirectory()) {
children = f.listFiles();
if (children!=null && children.length>0) {
// Non empty directory
for(File c : children) {
getLog().debug("Discovering: "+c); //$NON-NLS-1$
candidates.push(c);
}
}
else {
// empty directory
getLog().debug("Deleting: "+f); //$NON-NLS-1$
candidates.removeFirst();
f.delete();
buildContext.refresh(f.getParentFile());
}
}
else {
// not a directory
candidates.removeFirst();
if (f.exists()) {
getLog().debug("Deleting: "+f); //$NON-NLS-1$
f.delete();
buildContext.refresh(f.getParentFile());
}
}
}
getLog().debug("Deletion done"); //$NON-NLS-1$
}
}
/**
* Copy a file.
*
* @param in
* @param out
* @throws IOException
*/
public final void fileCopy(File in, File out) throws IOException {
assert (in != null);
assert (out != null);
getLog().debug("Copying file: "+in.toString()+" into "+out.toString()); //$NON-NLS-1$ //$NON-NLS-2$
FileInputStream fis = new FileInputStream(in);
FileChannel inChannel = fis.getChannel();
FileOutputStream fos = new FileOutputStream(out);
FileChannel outChannel = fos.getChannel();
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
}
finally {
outChannel.close();
fos.close();
inChannel.close();
fis.close();
getBuildContext().refresh(out);
}
}
/**
* Copy a file.
*
* @param in
* @param out
* @throws IOException
*/
public final void fileCopy(URL in, File out) throws IOException {
assert (in != null);
InputStream inStream = in.openStream();
OutputStream outStream = new FileOutputStream(out);
try {
byte[] buf = new byte[4096];
int len;
while ((len = inStream.read(buf)) > 0) {
outStream.write(buf, 0, len);
}
}
finally {
outStream.close();
inStream.close();
getBuildContext().refresh(out);
}
}
/**
* Read a resource property and replace the parametrized macros by the given parameters.
*
* @param source
* is the source of the properties.
* @param label
* is the name of the property.
* @param params
* are the parameters to replace.
* @return the read text.
*/
public static final String getLString(Class> source, String label, Object... params) {
ResourceBundle rb = ResourceBundle.getBundle(source.getCanonicalName());
String text = rb.getString(label);
text = text.replaceAll("[\\n\\r]", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
text = text.replaceAll("\\t", "\t"); //$NON-NLS-1$ //$NON-NLS-2$
text = MessageFormat.format(text, params);
return text;
}
/**
* Remove the path prefix from a file.
*
* @param prefix
* @param file
* @return the file without the prefix.
*/
public static final String removePathPrefix(File prefix, File file) {
String r = file.getAbsolutePath().replaceFirst(
"^"+ //$NON-NLS-1$
Pattern.quote(prefix.getAbsolutePath()),
EMPTY_STRING);
if (r.startsWith(File.separator))
return r.substring(File.separator.length());
return r;
}
/**
* Invocation date.
*/
protected final Date invocationDate = new Date();
/**
* Map the directory of pom.xml files to the definition of the corresponding maven module.
*/
private final Map localArtifactDescriptions = new TreeMap();
/**
* Map the artifact id to the definition of the corresponding maven module.
*/
private final Map remoteArtifactDescriptions = new TreeMap();
/**
* Manager of the SVN repository.
*/
private SVNClientManager svnManager = null;
/**
* Are the preferred charset in the preferred order.
*/
private Charset[] preferredCharsets;
/**
*/
public AbstractArakhneMojo() {
List availableCharsets = new ArrayList();
// New Mac OS and Linux OS
addCharset(availableCharsets, PREFERRED_CHARSET_UNIX);
// Windows OS
addCharset(availableCharsets, PREFERRED_CHARSET_WINDOWS);
// Old Mac OS
addCharset(availableCharsets, PREFERRED_CHARSET_MACOS);
// Java Internal
addCharset(availableCharsets, PREFERRED_CHARSET_JVM);
this.preferredCharsets = new Charset[availableCharsets.size()];
availableCharsets.toArray(this.preferredCharsets);
availableCharsets.clear();
}
private static void addCharset(List availableCharsets, String csName) {
try {
Charset cs = Charset.forName(csName);
if (!availableCharsets.contains(cs)) {
availableCharsets.add(cs);
}
} catch (Throwable _) {
//
}
}
/**
* Replies the preferred charsets in the preferred order of use.
*
* @return the preferred charsets in the preferred order of use.
*/
public final Charset[] getPreferredCharsets() {
return this.preferredCharsets;
}
/**
* Set the preferred charsets in the preferred order of use.
*
* @param charsets
* are the preferred charsets in the preferred order of use.
*/
public final void setPreferredCharsets(Charset... charsets) {
this.preferredCharsets = charsets;
}
/**
* Replies the manager of the SVN repository.
*
* @return the manager of the SVN repository.
*/
public final synchronized SVNClientManager getSVNClientManager() {
if (this.svnManager == null) {
this.svnManager = SVNClientManager.newInstance();
}
return this.svnManager;
}
/**
* Replies the artifact handler manager.
*
* It is an attribute defined as:
* /* @component
* */
* private ArtifactHandlerManager manager;
*
*
* @return the artifact resolver.
*/
public abstract ArtifactHandlerManager getArtifactHandlerManager();
/**
* Replies the output directory of the project. Basically it is getRootDirectory()+"/target"
.
*
* It is an attribute defined as:
* /* @parameter expression="${project.build.directory}"
* */
* private File outputDirectory;
*
*
* @return the output directory.
*/
public abstract File getOutputDirectory();
/**
* Replies the root directory of the project. Basically it is the value stored inside the Maven property named project.basedir
.
*
* It is an attribute defined as:
* /* @parameter expression="${project.basedir}"
* */
* private File baseDirectory;
*
*
* @return the root directory.
*/
public abstract File getBaseDirectory();
/** Replies the build context that may be used during Mojo execution.
* This build context permits to be used inside and outside the
* Eclipse IDE.
*
* @return the build context.
*/
public abstract BuildContext getBuildContext();
/**
* Replies the current maven session. Basically it is an internal component of Maven.
*
* It is an attribute defined as:
* /* @component role="org.apache.maven.project.MavenProjectBuilder"
* * @required
* * @readonly
* */
* private MavenProjectBuilder projectBuilder;
*
*
* @return the maven session
*/
public abstract MavenProjectBuilder getMavenProjectBuilder();
/**
* Replies the current project builder. Basically it is an internal component of Maven.
*
* It is an attribute defined as:
* /* @parameter expression="${session}"
* * @required
* */
* private MavenSession mvnSession;
*
*
* @return the maven session
*/
public abstract MavenSession getMavenSession();
/**
* Search and reply the maven artifact which is corresponding to the given file.
*
* @param file
* is the file for which the maven artifact should be retreived.
* @return the maven artifact or null
if none.
*/
public final synchronized ExtendedArtifact searchArtifact(File file) {
String filename = removePathPrefix(getBaseDirectory(), file);
getLog().debug("Retreiving module for " + filename); //$NON-NLS-1$
File theFile = file;
File pomDirectory = null;
while (theFile != null && pomDirectory == null) {
if (theFile.isDirectory()) {
File pomFile = new File(theFile, "pom.xml"); //$NON-NLS-1$
if (pomFile.exists()) {
pomDirectory = theFile;
}
}
theFile = theFile.getParentFile();
}
if (pomDirectory != null) {
ExtendedArtifact a = this.localArtifactDescriptions.get(pomDirectory);
if (a == null) {
a = readPom(pomDirectory);
this.localArtifactDescriptions.put(pomDirectory, a);
getLog().debug("Found local module description for " //$NON-NLS-1$
+ a.toString());
}
return a;
}
BuildContext buildContext = getBuildContext();
buildContext.addMessage(file,
1, 1,
"The maven module for this file cannot be retreived.", //$NON-NLS-1$
BuildContext.SEVERITY_WARNING, null);
return null;
}
/**
* Replies the project's remote repositories to use for the resolution of plugins and their dependencies..
*
* It is an attribute defined as:
* /* @parameter default-value="${project.remoteProjectRepositories}"
* */
* private List remoteRepos;
*
*
* @return the repository system
*/
public abstract List getRemoteRepositoryList();
/**
* Replies the repository system used by this maven instance. Basically it is an internal component of Maven.
*
* It is an attribute defined as:
* /* @component
* */
* private RepositorySystem repoSystem;
*
*
* @return the repository system
*/
public abstract RepositorySystem getRepositorySystem();
/**
* Replies the current repository/network configuration of Maven..
*
* It is an attribute defined as:
* /* @parameter default-value="${repositorySystemSession}"
* @readonly
* */
* private RepositorySystemSession repoSession;
*
*
* @return the repository system
*/
public abstract RepositorySystemSession getRepositorySystemSession();
/**
* Retreive the extended artifact definition of the given artifact.
* @param mavenArtifact - the artifact to resolve
* @return the artifact definition.
* @throws MojoExecutionException
*/
public final Artifact resolveArtifact(Artifact mavenArtifact) throws MojoExecutionException {
org.eclipse.aether.artifact.Artifact aetherArtifact = createArtifact(mavenArtifact);
ArtifactRequest request = new ArtifactRequest();
request.setArtifact(aetherArtifact);
request.setRepositories(getRemoteRepositoryList());
ArtifactResult result;
try {
result = getRepositorySystem().resolveArtifact( getRepositorySystemSession(), request );
}
catch (ArtifactResolutionException e) {
throw new MojoExecutionException( e.getMessage(), e );
}
return createArtifact(result.getArtifact());
}
/**
* Retreive the extended artifact definition of the given artifact id.
*
* @param groupId
* is the identifier of the group.
* @param artifactId
* is the identifier of the artifact.
* @param version
* is the version of the artifact to retreive.
* @return the artifact definition.
* @throws MojoExecutionException
*/
public final Artifact resolveArtifact(String groupId, String artifactId, String version) throws MojoExecutionException {
return resolveArtifact(createArtifact(groupId, artifactId, version));
}
/**
* Replies a list of files which are found on the file system.
*
* @param directory
* is the directory to search in.
* @param filter
* is the file selector
* @return the list of files.
*/
public final Collection findFiles(File directory, FileFilter filter) {
Collection files = new ArrayList();
findFiles(directory, filter, files);
return files;
}
/**
* Replies a list of files which are found on the file system.
*
* @param directory
* is the directory to search in.
* @param filter
* is the file selector
* @param fileOut
* is the list of files to fill.
*/
public final synchronized void findFiles(File directory, FileFilter filter, Collection super File> fileOut) {
if (directory != null && filter != null) {
File candidate;
List candidates = new ArrayList();
String relativePath = removePathPrefix(getBaseDirectory(), directory);
getLog().debug("Retreiving " //$NON-NLS-1$
+ filter.toString() + " files from " //$NON-NLS-1$
+ relativePath);
candidates.add(directory);
int nbFiles = 0;
while (!candidates.isEmpty()) {
candidate = candidates.remove(0);
if (candidate.isDirectory()) {
File[] children = candidate.listFiles(filter);
if (children != null) {
for (File child : children) {
if (child != null && child.isDirectory()) {
candidates.add(child);
} else {
fileOut.add(child);
++nbFiles;
}
}
}
}
}
getLog().debug("Found " //$NON-NLS-1$
+ nbFiles + " file(s)"); //$NON-NLS-1$
}
}
/**
* Replies a map of files which are found on the file system. The map has the found files as keys and the search directory as values.
*
* @param directory
* is the directory to search in.
* @param filter
* is the file selector
* @param fileOut
* is the list of files to fill.
*/
public final synchronized void findFiles(File directory, FileFilter filter, Map super File, File> fileOut) {
findFiles(directory, filter, fileOut, null);
}
/**
* Replies a map of files which are found on the file system. The map has the found files as keys and the search directory as values.
*
* @param directory
* is the directory to search in.
* @param filter
* is the file selector
* @param fileOut
* is the list of files to fill.
* @param listener on the files that are not matching the file filter.
*/
public final synchronized void findFiles(File directory, FileFilter filter, Map super File, File> fileOut,
FindFileListener listener) {
if (directory != null && filter != null) {
File candidate;
List candidates = new ArrayList();
String relativePath = removePathPrefix(getBaseDirectory(), directory);
getLog().debug("Retreiving " //$NON-NLS-1$
+ filter.toString() + " files from " //$NON-NLS-1$
+ relativePath);
candidates.add(directory);
int nbFiles = 0;
while (!candidates.isEmpty()) {
candidate = candidates.remove(0);
if (candidate.isDirectory()) {
File[] children = candidate.listFiles();
if (children != null) {
for (File child : children) {
if (child != null && child.isDirectory()) {
candidates.add(child);
}
else if (filter.accept(child)) {
fileOut.put(child, directory);
++nbFiles;
}
else if (listener!=null) {
listener.findFile(child, directory);
}
}
}
}
}
getLog().debug("Found " //$NON-NLS-1$
+ nbFiles + " file(s)"); //$NON-NLS-1$
}
}
/**
* Replies the maven artifact which is described by the pom.xml
file in the given directory.
*
* @param pomDirectory
* is the directory where to find the pom.xml
file.
* @return the artifact or null
.
*/
public synchronized final ExtendedArtifact readPom(File pomDirectory) {
return readPomFile(new File(pomDirectory, "pom.xml")); //$NON-NLS-1$
}
/**
* Replies the maven artifact which is described by the given pom.xml
.
*
* @param pomFile
* is the pom.xml
file.
* @return the artifact or null
.
*/
public synchronized final ExtendedArtifact readPomFile(File pomFile) {
String groupId = null;
String artifactId = null;
String name = null;
String version = null;
String url = null;
Organization organization = null;
Scm scm = null;
List developers;
List contributors;
List licenses;
Parent parent = null;
getLog().debug("Read pom file: " + pomFile.toString()); //$NON-NLS-1$
if (!pomFile.canRead())
return null;
MavenXpp3Reader pomReader = new MavenXpp3Reader();
try {
FileReader fr = new FileReader(pomFile);
try {
Model model = pomReader.read(fr);
groupId = model.getGroupId();
artifactId = model.getArtifactId();
name = model.getName();
version = model.getVersion();
url = model.getUrl();
organization = model.getOrganization();
scm = model.getScm();
developers = model.getDevelopers();
contributors = model.getContributors();
licenses = model.getLicenses();
parent = model.getParent();
}
catch (IOException e) {
return null;
}
catch (XmlPullParserException e) {
return null;
}
finally {
fr.close();
}
}
catch (IOException e) {
return null;
}
if (developers == null) {
developers = new ArrayList();
} else {
List list = new ArrayList();
list.addAll(developers);
developers = list;
}
if (contributors == null) {
contributors = new ArrayList();
} else {
List list = new ArrayList();
list.addAll(contributors);
contributors = list;
}
if (licenses == null) {
licenses = new ArrayList();
} else {
List list = new ArrayList();
list.addAll(licenses);
licenses = list;
}
if (parent != null) {
String relPath = parent.getRelativePath();
File parentPomDirectory = new File(pomFile.getParentFile(), relPath);
try {
parentPomDirectory = parentPomDirectory.getCanonicalFile();
if (!parentPomDirectory.isDirectory()) {
parentPomDirectory = parentPomDirectory.getParentFile();
}
ExtendedArtifact parentArtifact = this.localArtifactDescriptions.get(parentPomDirectory);
if (parentArtifact == null) {
parentArtifact = readPom(parentPomDirectory);
if (parentArtifact != null) {
this.localArtifactDescriptions.put(parentPomDirectory, parentArtifact);
getLog().debug("Add local module description for " //$NON-NLS-1$
+ parentArtifact.toString());
} else {
String key = ArtifactUtils.key(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
Artifact artifact = createArtifact(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
ArtifactRepository repo = getMavenSession().getLocalRepository();
String artifactPath = repo.pathOf(artifact);
artifactPath = artifactPath.replaceFirst("\\.jar$", ".pom"); //$NON-NLS-1$ //$NON-NLS-2$
File artifactFile = new File(repo.getBasedir(), artifactPath);
getLog().debug("Getting pom file in local repository for " //$NON-NLS-1$
+ key + ": " + artifactFile.getAbsolutePath()); //$NON-NLS-1$
BuildContext buildContext = getBuildContext();
buildContext.removeMessages(pomFile);
if (artifactFile.canRead()) {
parentArtifact = readPomFile(artifactFile);
if (parentArtifact != null) {
this.remoteArtifactDescriptions.put(key, parentArtifact);
getLog().debug("Add remote module description for " //$NON-NLS-1$
+ parentArtifact.toString());
}
else {
buildContext.addMessage(
pomFile,
1, 1,
"Unable to retreive the pom file of " + key, //$NON-NLS-1$
BuildContext.SEVERITY_WARNING, null);
}
}
else {
buildContext.addMessage(
pomFile,
1, 1,
"Cannot read the file for '" + key + "': " + artifactFile.getAbsolutePath(), //$NON-NLS-1$ //$NON-NLS-2$
BuildContext.SEVERITY_WARNING, null);
}
}
}
if (parentArtifact != null) {
developers.addAll(parentArtifact.getDevelopers());
contributors.addAll(parentArtifact.getContributors());
}
} catch (IOException e) {
getLog().warn(e);
}
// Be sure that the optional fields version and groupId are correctly set.
if (version==null || version.isEmpty()) {
version = parent.getVersion();
}
if (groupId==null || groupId.isEmpty()) {
groupId = parent.getGroupId();
}
}
String scmRevision = null;
try {
SVNClientManager svnManager = getSVNClientManager();
SVNInfo svnInfo = svnManager.getWCClient().doInfo(pomFile.getParentFile(), SVNRevision.UNDEFINED);
if (svnInfo != null) {
SVNRevision revision = svnInfo.getRevision();
if (revision != null) {
scmRevision = Long.toString(revision.getNumber());
}
}
} catch (SVNException _) {
//
}
Artifact a = createArtifact(groupId, artifactId, version);
return new ExtendedArtifact(a, name, url, organization, scmRevision, scm, developers, contributors, licenses);
}
/**
* Create an Jar runtime artifact from the given values.
*
* @param groupId
* @param artifactId
* @param version
* @return the artifact
*/
public final Artifact createArtifact(String groupId, String artifactId, String version) {
return createArtifact(groupId, artifactId, version, "runtime", "jar"); //$NON-NLS-1$//$NON-NLS-2$
}
/** Convert the maven artifact to Aether artifact.
*
* @param a - the maven artifact.
* @return the Aether artifact.
*/
protected final static org.eclipse.aether.artifact.Artifact createArtifact(Artifact a) {
return new DefaultArtifact(
a.getGroupId(),
a.getArtifactId(),
a.getClassifier(),
a.getType(),
a.getVersion());
}
/** Convert the Aether artifact to maven artifact.
*
* @param a - the Aether artifact.
* @return the maven artifact.
*/
protected final Artifact createArtifact(org.eclipse.aether.artifact.Artifact a) {
return createArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
}
/**
* Create an artifact from the given values.
*
* @param groupId
* @param artifactId
* @param version
* @param scope
* @param type
* @return the artifact
*/
public final Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type) {
VersionRange versionRange = null;
if (version != null) {
versionRange = VersionRange.createFromVersion(version);
}
String desiredScope = scope;
if (Artifact.SCOPE_TEST.equals(desiredScope)) {
desiredScope = Artifact.SCOPE_TEST;
}
if (Artifact.SCOPE_PROVIDED.equals(desiredScope)) {
desiredScope = Artifact.SCOPE_PROVIDED;
}
if (Artifact.SCOPE_SYSTEM.equals(desiredScope)) {
// system scopes come through unchanged...
desiredScope = Artifact.SCOPE_SYSTEM;
}
ArtifactHandler handler = getArtifactHandlerManager().getArtifactHandler(type);
return new org.apache.maven.artifact.DefaultArtifact(
groupId, artifactId, versionRange,
desiredScope, type, null, // classifier
handler, false); // optional
}
/**
* Check if the values of the attributes of this Mojo are correctly set. This function may be overridden by subclasses to test subclasse's attributes.
*
* @throws MojoExecutionException
*/
protected abstract void checkMojoAttributes() throws MojoExecutionException;
private static String getLogType(Object o) {
if (o instanceof Boolean || o instanceof AtomicBoolean)
return "B"; //$NON-NLS-1$
if (o instanceof Byte)
return "b"; //$NON-NLS-1$
if (o instanceof Short)
return "s"; //$NON-NLS-1$
if (o instanceof Integer || o instanceof AtomicInteger)
return "i"; //$NON-NLS-1$
if (o instanceof Long || o instanceof AtomicLong)
return "l"; //$NON-NLS-1$
if (o instanceof Float)
return "f"; //$NON-NLS-1$
if (o instanceof Double)
return "d"; //$NON-NLS-1$
if (o instanceof BigDecimal)
return "D"; //$NON-NLS-1$
if (o instanceof BigInteger)
return "I"; //$NON-NLS-1$
if (o instanceof CharSequence)
return "s"; //$NON-NLS-1$
if (o instanceof Array) {
Array a = (Array) o;
return a.getClass().getComponentType().getName() + "[]"; //$NON-NLS-1$
}
if (o instanceof Set>)
return "set"; //$NON-NLS-1$
if (o instanceof Map, ?>)
return "map"; //$NON-NLS-1$
if (o instanceof List>)
return "list"; //$NON-NLS-1$
if (o instanceof Collection>)
return "col"; //$NON-NLS-1$
return "o"; //$NON-NLS-1$
}
/**
* Throw an exception when the given object is null.
*
* @param message
* is the message to put in the exception.
* @param o
*/
protected final void assertNotNull(String message, Object o) {
if (getLog().isDebugEnabled()) {
getLog().debug(
"\t(" //$NON-NLS-1$
+ getLogType(o)
+ ") " //$NON-NLS-1$
+ message
+ " = " //$NON-NLS-1$
+ o);
}
if (o == null)
throw new AssertionError("assertNotNull: " + message); //$NON-NLS-1$
}
/**
* {@inheritDoc}
*/
@Override
public final void execute() throws MojoExecutionException {
try {
checkMojoAttributes();
executeMojo();
} finally {
clearInternalBuffers();
}
}
/**
* Clear internal buffers.
*/
protected synchronized void clearInternalBuffers() {
this.localArtifactDescriptions.clear();
this.remoteArtifactDescriptions.clear();
}
/**
* Invoked when the Mojo should be executed.
*
* @throws MojoExecutionException
*/
protected abstract void executeMojo() throws MojoExecutionException;
/**
* Join the values with the given joint
*
* @param joint
* @param values
* @return the jointed values
*/
public static String join(String joint, String... values) {
StringBuilder b = new StringBuilder();
for (String value : values) {
if (value != null && !EMPTY_STRING.equals(value)) {
if (b.length() > 0) {
b.append(joint);
}
b.append(value);
}
}
return b.toString();
}
private static void detectEncoding(File file, CharsetDecoder decoder) throws IOException, CharacterCodingException {
decoder.onMalformedInput(CodingErrorAction.REPORT);
decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
FileInputStream fis = new FileInputStream(file);
ReadableByteChannel channel = Channels.newChannel(fis);
Reader reader = Channels.newReader(channel, decoder, -1);
BufferedReader bReader = new BufferedReader(reader);
try {
String line = bReader.readLine();
while (line != null) {
line = bReader.readLine();
}
}
finally {
bReader.close();
reader.close();
channel.close();
fis.close();
}
}
/**
* Try to detect and reply the encoding of the given file. This function uses the charsets replied by {@link #getPreferredCharsets()} to select a charset when many are possible.
*
* @param file
* is the file to read.
* @return the encoding charset of the given file or null
if the encoding could not be detected.
* @see #getPreferredCharsets()
* @see #setPreferredCharsets(Charset...)
*/
public final Charset detectEncoding(File file) {
Collection fittingCharsets = new TreeSet();
for (Charset c : Charset.availableCharsets().values()) {
CharsetDecoder decoder = c.newDecoder();
try {
detectEncoding(file, decoder);
fittingCharsets.add(c);
} catch (Throwable e) {
//
}
}
if (getLog().isDebugEnabled()) {
getLog().debug("Valid charsets for " + file.getName() + ":\n" + fittingCharsets.toString()); //$NON-NLS-1$ //$NON-NLS-2$
}
for (Charset prefCharset : getPreferredCharsets()) {
if (prefCharset.canEncode() && fittingCharsets.contains(prefCharset)) {
getLog().debug("Use preferred charset for " + file.getName() + ": " + prefCharset.displayName()); //$NON-NLS-1$ //$NON-NLS-2$
return prefCharset;
}
}
Charset platformCharset = Charset.defaultCharset();
if (platformCharset.canEncode() && fittingCharsets.contains(platformCharset)) {
getLog().debug("Use platform default charset for " + file.getName() + ": " + platformCharset.displayName()); //$NON-NLS-1$ //$NON-NLS-2$
return Charset.defaultCharset();
}
Iterator iterator = fittingCharsets.iterator();
while (iterator.hasNext()) {
Charset c = iterator.next();
if (c.canEncode()) {
getLog().debug("Use first valid charset for " + file.getName() + ": " + c.displayName()); //$NON-NLS-1$ //$NON-NLS-2$
return c;
}
}
return null;
}
/** Replies the dependencies specified in the the Maven configuration
* of the current project.
*
* @param isTransitive indicates if the dependencies of dependencies
* must also be replied by the iterator.
* @return the iterator.
* @see #getDependencies(MavenProject, boolean)
*/
public final Iterator getDependencies(boolean isTransitive) {
return getDependencies(getMavenSession().getCurrentProject(), isTransitive);
}
/** Replies the dependencies specified in the the Maven configuration
* of the given project.
*
* @param project is the maven project for which the dependencies must be replied.
* @param isTransitive indicates if the dependencies of dependencies
* must also be replied by the iterator.
* @return the iterator.
* @see #getDependencies(boolean)
*/
public final Iterator getDependencies(MavenProject project, boolean isTransitive) {
return new DependencyIterator(project, isTransitive);
}
/** Replies the plugins specified in the the Maven configuration
* of the current project.
*
* @param isTransitive indicates if the plugins of dependencies
* must also be replied by the iterator.
* @return the iterator.
* @see #getPlugins(MavenProject, boolean)
*/
public final Iterator getPlugins(boolean isTransitive) {
return getPlugins(getMavenSession().getCurrentProject(), isTransitive);
}
/** Replies the plugins specified in the the Maven configuration
* of the given project.
*
* @param project is the maven project for which the plugins must be replied.
* @param isTransitive indicates if the plugins of dependencies
* must also be replied by the iterator.
* @return the iterator.
* @see #getPlugins(boolean)
*/
public final Iterator getPlugins(MavenProject project, boolean isTransitive) {
return new PluginIterator(project, isTransitive);
}
/** Load the Maven project for the given artifact.
*
* @param artifact
* @return the maven project.
*/
public MavenProject getMavenProject(Artifact artifact) {
try {
MavenSession session = getMavenSession();
MavenProject current = session.getCurrentProject();
MavenProject prj = getMavenProjectBuilder().buildFromRepository(
artifact,
current.getRemoteArtifactRepositories(),
session.getLocalRepository());
return prj;
}
catch (ProjectBuildingException e) {
getLog().warn(e);
}
return null;
}
/**
* @author Stéphane GALLAND
* @version 12.0 2015-04-09 01:25:33
* @mavengroupid org.arakhne.afc.maven
* @mavenartifactid maventools
*/
private class DependencyIterator implements Iterator {
private final List remoteRepositiories;
private final boolean isTransitive;
private final File projectFile;
private List dependencies = new ArrayList();
private Set treated = new TreeSet();
private MavenProject next;
/**
* @param project is the project for which the dependencies must
* be replied.
* @param isTransitive indicates if the dependencies of dependencies must also be replied
* by the iterator.
*/
public DependencyIterator(MavenProject project, boolean isTransitive) {
this.isTransitive = isTransitive;
this.remoteRepositiories = project.getRemoteArtifactRepositories();
this.dependencies.addAll(project.getDependencies());
this.projectFile = project.getFile();
getBuildContext().removeMessages(this.projectFile);
searchNext();
}
private void searchNext() {
this.next = null;
while (this.next==null && !this.dependencies.isEmpty()) {
Dependency dependency = this.dependencies.remove(0);
if (dependency!=null) {
String artifactId = dependency.getGroupId()+":"+dependency.getArtifactId()+":"+dependency.getVersion(); //$NON-NLS-1$//$NON-NLS-2$
if (!this.treated.contains(artifactId)) {
boolean isTreated = false;
try {
Artifact dependencyArtifact = createArtifact(
dependency.getGroupId(),
dependency.getArtifactId(),
dependency.getVersion(),
dependency.getScope(),
dependency.getType());
resolveArtifact(dependencyArtifact);
MavenProjectBuilder builder = getMavenProjectBuilder();
MavenProject dependencyProject = builder.buildFromRepository(
dependencyArtifact,
this.remoteRepositiories,
getMavenSession().getLocalRepository());
if (dependencyProject!=null) {
if (this.isTransitive) {
this.dependencies.addAll(dependencyProject.getDependencies());
}
this.next = dependencyProject;
isTreated = true;
}
}
catch (MojoExecutionException e) {
getBuildContext().addMessage(
this.projectFile,
1,1,
"Unable to retreive the Maven plugin: "+artifactId, //$NON-NLS-1$
BuildContext.SEVERITY_WARNING,
e);
isTreated = true;
}
catch (ProjectBuildingException e) {
getBuildContext().addMessage(
this.projectFile,
1,1,
"Unable to retreive the Maven plugin: "+artifactId, //$NON-NLS-1$
BuildContext.SEVERITY_WARNING,
e);
isTreated = true;
}
if (isTreated) this.treated.add(artifactId);
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return this.next!=null;
}
/**
* {@inheritDoc}
*/
@Override
public MavenProject next() {
MavenProject n = this.next;
if (n==null) throw new NoSuchElementException();
searchNext();
return n;
}
/**
* {@inheritDoc}
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
} // class DependencyIterator
/**
* @author Stéphane GALLAND
* @version 12.0 2015-04-09 01:25:33
* @mavengroupid org.arakhne.afc.maven
* @mavenartifactid maventools
*/
private class PluginIterator implements Iterator {
private final Iterator dependencyIterator;
private Iterator pluginIterator;
private Plugin next;
/**
* @param project
* @param isTransitive
*/
public PluginIterator(MavenProject project, boolean isTransitive) {
this.dependencyIterator = getDependencies(project, isTransitive);
searchNext();
}
private void searchNext() {
this.next = null;
while (this.next==null) {
if (this.pluginIterator!=null && this.pluginIterator.hasNext()) {
this.next = this.pluginIterator.next();
}
else if (this.dependencyIterator.hasNext()) {
MavenProject project = this.dependencyIterator.next();
List buildPlugins = project.getBuildPlugins();
if (buildPlugins!=null) {
this.pluginIterator = buildPlugins.iterator();
}
}
else {
return;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return this.next!=null;
}
/**
* {@inheritDoc}
*/
@Override
public Plugin next() {
org.apache.maven.model.Plugin n = this.next;
if (n==null) throw new NoSuchElementException();
searchNext();
return n;
}
/**
* {@inheritDoc}
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
} // class PluginIterator
/**
* Abstract implementation for all Arakhnê maven modules. This implementation is thread safe.
*
* @author Stéphane GALLAND
* @version 12.0 2015-04-09 01:25:33
* @mavengroupid org.arakhne.afc.maven
* @mavenartifactid maventools
*
* @component
*/
public static interface FindFileListener extends EventListener {
/** Invoked when a file which is not matching the file filter was found.
*
* @param file is the file that is not matching the file filter.
* @param rootDirectory is the root directory in which the file was found.
*/
public void findFile(File file, File rootDirectory);
} // interface FindFileListener
}