All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.arakhne.maven.AbstractArakhneMojo Maven / Gradle / Ivy

There is a newer version: 17.0
Show newest version
/* 
 * $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 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 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 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 }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy