/* ==========================================================================
* Copyright 2003-2004 Mevenide Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================================================================
*/
package org.codehaus.mojo.nbm;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactCollector;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
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.shared.dependency.tree.DependencyNode;
import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Taskdef;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.codehaus.mojo.nbm.model.Dependency;
import org.codehaus.mojo.nbm.model.NetbeansModule;
import org.codehaus.mojo.nbm.model.io.xpp3.NetbeansModuleXpp3Reader;
import org.codehaus.plexus.util.IOUtil;
public abstract class AbstractNbmMojo
extends AbstractMojo
{
protected final Project registerNbmAntTasks()
{
Project antProject = new Project();
antProject.init();
Taskdef taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( "org.netbeans.nbbuild.MakeListOfNBM" );
taskdef.setName( "genlist" );
taskdef.execute();
taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( "org.netbeans.nbbuild.MakeNBM" );
taskdef.setName( "makenbm" );
taskdef.execute();
taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( "org.netbeans.nbbuild.MakeUpdateDesc" );
taskdef.setName( "updatedist" );
taskdef.execute();
taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( "org.netbeans.nbbuild.CreateModuleXML" );
taskdef.setName( "createmodulexml" );
taskdef.execute();
taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( "org.netbeans.nbbuild.JHIndexer" );
taskdef.setName( "jhindexer" );
taskdef.execute();
return antProject;
}
static final boolean matchesLibrary( Artifact artifact, List<String> libraries, ExamineManifest depExaminator,
Log log, boolean useOsgiDependencies )
{
String artId = artifact.getArtifactId();
String grId = artifact.getGroupId();
String id = grId + ":" + artId;
boolean explicit = libraries.remove( id );
if ( explicit )
{
log.debug(
id + " included as module library, explicitly declared in module descriptor." );
return explicit;
}
if ( Artifact.SCOPE_PROVIDED.equals( artifact.getScope() ) || Artifact.SCOPE_SYSTEM.equals(
artifact.getScope() ) )
{
log.debug(
id + " omitted as module library, has scope 'provided/system'" );
return false;
}
if ( "nbm".equals( artifact.getType() ) )
{
return false;
}
if ( depExaminator.isNetbeansModule() || (useOsgiDependencies && depExaminator.isOsgiBundle()) )
{
//TODO I can see how someone might want to include an osgi bundle as library, not dependency.
// I guess it won't matter much in 6.9+, in older versions it could be a problem.
return false;
}
log.debug(
id + " included as module library, squeezed through all the filters." );
return true;
}
static Dependency resolveNetbeansDependency( Artifact artifact, List<Dependency> deps,
ExamineManifest manifest, Log log )
{
String artId = artifact.getArtifactId();
String grId = artifact.getGroupId();
String id = grId + ":" + artId;
for ( Dependency dep : deps )
{
if ( id.equals( dep.getId() ) )
{
if ( manifest.isNetbeansModule() )
{
return dep;
}
else
{
if ( dep.getExplicitValue() != null )
{
return dep;
}
log.warn(
id + " declared as module dependency in descriptor, but not a NetBeans module" );
return null;
}
}
}
if ( "nbm".equals( artifact.getType() ) )
{
Dependency dep = new Dependency();
dep.setId( id );
dep.setType( "spec" );
log.debug( "Adding nbm module dependency - " + id );
return dep;
}
if ( manifest.isNetbeansModule() )
{
Dependency dep = new Dependency();
dep.setId( id );
dep.setType( "spec" );
log.debug( "Adding direct NetBeans module dependency - " + id );
return dep;
}
return null;
}
protected final NetbeansModule readModuleDescriptor( File descriptor )
throws MojoExecutionException
{
if ( descriptor == null )
{
throw new MojoExecutionException(
"The module descriptor has to be configured." );
}
if ( !descriptor.exists() )
{
throw new MojoExecutionException(
"The module descriptor is missing: '" + descriptor + "'." );
}
Reader r = null;
try
{
r = new FileReader( descriptor );
NetbeansModuleXpp3Reader reader = new NetbeansModuleXpp3Reader();
NetbeansModule module = reader.read( r );
return module;
}
catch ( IOException exc )
{
throw new MojoExecutionException(
"Error while reading module descriptor '" + descriptor + "'.",
exc );
}
catch ( XmlPullParserException xml )
{
throw new MojoExecutionException(
"Error while reading module descriptor '" + descriptor + "'.",
xml );
}
finally
{
IOUtil.close( r );
}
}
protected final NetbeansModule createDefaultDescriptor( MavenProject project, boolean log )
{
if ( log )
{
getLog().info(
"No Module Descriptor defined, trying to fallback to generated values:" );
}
NetbeansModule module = new NetbeansModule();
module.setAuthor( "Nobody" );
module.setCluster( "maven" );
if ( log )
{
getLog().info( " Cluster:" + module.getCluster() );
}
// same code in Nb IDE, keep it synchronized with MavenNbModuleImpl.getCodeNameBase()
String codename = project.getGroupId() + "." + project.getArtifactId();
codename = codename.replaceAll( "-", "." );
module.setCodeNameBase( codename );
if ( log )
{
getLog().info( " Codenamebase:" + module.getCodeNameBase() );
}
module.setModuleType( "normal" );
if ( log )
{
getLog().info( " Type:" + module.getModuleType() );
}
module.setRequiresRestart( false );
return module;
}
static List<Artifact> getLibraryArtifacts( DependencyNode treeRoot, NetbeansModule module,
List<Artifact> runtimeArtifacts, Map<Artifact, ExamineManifest> examinerCache,
Log log, boolean useOsgiDependencies ) throws MojoExecutionException
{
List<Artifact> include = new ArrayList<Artifact>();
if ( module != null )
{
List<String> librList = new ArrayList<String>();
if ( module.getLibraries() != null )
{
librList.addAll( module.getLibraries() );
}
CollectLibrariesNodeVisitor visitor = new CollectLibrariesNodeVisitor( librList,
runtimeArtifacts, examinerCache, log, treeRoot, useOsgiDependencies );
treeRoot.accept( visitor );
include.addAll( visitor.getArtifacts() );
}
return include;
}
static List<ModuleWrapper> getModuleDependencyArtifacts( DependencyNode treeRoot, NetbeansModule module,
MavenProject project, Map<Artifact, ExamineManifest> examinerCache,
List<Artifact> libraryArtifacts, Log log, boolean useOsgiDependencies ) throws MojoExecutionException
{
List<ModuleWrapper> include = new ArrayList<ModuleWrapper>();
if ( module != null )
{
List<Dependency> deps = module.getDependencies();
@SuppressWarnings( "unchecked" )
List<Artifact> artifacts = project.getCompileArtifacts();
for ( Artifact artifact : artifacts )
{
if ( libraryArtifacts.contains( artifact ) )
{
continue;
}
ExamineManifest depExaminator = examinerCache.get( artifact );
if ( depExaminator == null )
{
depExaminator = new ExamineManifest( log );
depExaminator.setJarFile( artifact.getFile() );
depExaminator.checkFile();
examinerCache.put( artifact, depExaminator );
}
Dependency dep = resolveNetbeansDependency( artifact, deps,
depExaminator, log );
if ( dep != null )
{
ModuleWrapper wr = new ModuleWrapper();
wr.dependency = dep;
wr.artifact = artifact;
wr.transitive = false;
//only direct deps matter to us..
if ( depExaminator.isNetbeansModule() && artifact.getDependencyTrail().size() > 2 )
{
log.debug(
artifact.getId() + " omitted as NetBeans module dependency, not a direct one. Declare it in the pom for inclusion." );
wr.transitive = true;
}
include.add( wr );
} else {
if ( useOsgiDependencies && depExaminator.isOsgiBundle() )
{
ModuleWrapper wr = new ModuleWrapper();
String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
for ( Dependency depe : deps )
{
if ( id.equals( depe.getId() ) )
{
wr.dependency = depe;
}
}
boolean print = false;
if ( wr.dependency == null)
{
Dependency depe = new Dependency();
depe.setId( id );
depe.setType( "spec" );
wr.dependency = depe;
print = true;
}
wr.artifact = artifact;
wr.transitive = false;
//only direct deps matter to us..
if ( artifact.getDependencyTrail().size() > 2 )
{
log.debug(
artifact.getId() + " omitted as NetBeans module OSGi dependency, not a direct one. Declare it in the pom for inclusion." );
wr.transitive = true;
} else {
if (print) log.info( "Adding OSGi bundle dependency - " + id );
}
include.add( wr );
}
}
}
}
return include;
}
static class ModuleWrapper
{
Dependency dependency;
Artifact artifact;
boolean transitive = true;
}
//copied from dependency:tree mojo
protected DependencyNode createDependencyTree( MavenProject project,
DependencyTreeBuilder dependencyTreeBuilder, ArtifactRepository localRepository,
ArtifactFactory artifactFactory, ArtifactMetadataSource artifactMetadataSource,
ArtifactCollector artifactCollector,
String scope ) throws MojoExecutionException
{
ArtifactFilter artifactFilter = createResolvingArtifactFilter( scope );
try
{
// TODO: note that filter does not get applied due to MNG-3236
return dependencyTreeBuilder.buildDependencyTree( project,
localRepository, artifactFactory,
artifactMetadataSource, artifactFilter, artifactCollector );
}
catch ( DependencyTreeBuilderException exception )
{
throw new MojoExecutionException( "Cannot build project dependency tree", exception );
}
}
//copied from dependency:tree mojo
/**
* Gets the artifact filter to use when resolving the dependency tree.
*
* @return the artifact filter
*/
private ArtifactFilter createResolvingArtifactFilter( String scope )
{
ArtifactFilter filter;
// filter scope
if ( scope != null )
{
getLog().debug( "+ Resolving dependency tree for scope '" + scope + "'" );
filter = new ScopeArtifactFilter( scope );
}
else
{
filter = null;
}
return filter;
}
protected final ArtifactResult turnJarToNbmFile( Artifact art, ArtifactFactory artifactFactory,
ArtifactResolver artifactResolver, MavenProject project, ArtifactRepository localRepository ) throws MojoExecutionException
{
if ( "jar".equals( art.getType() ) || "nbm".equals( art.getType() ) )
{
//TODO, it would be nice to have a check to see if the
// "to-be-created" module nbm artifact is actually already in the
// list of dependencies (as "nbm-file") or not..
// that would be a timesaver
ExamineManifest mnf = new ExamineManifest( getLog() );
File jar = art.getFile();
if ( ! jar.isFile() )
{
getLog().warn( "MNBMODULE-131: need to at least run package phase on " + jar );
return new ArtifactResult(null, null);
}
mnf.setJarFile( jar);
mnf.checkFile();
if ( mnf.isNetbeansModule() )
{
Artifact nbmArt = artifactFactory.createDependencyArtifact(
art.getGroupId(),
art.getArtifactId(),
art.getVersionRange(),
"nbm-file",
art.getClassifier(),
art.getScope() );
try
{
artifactResolver.resolve( nbmArt, project.getRemoteArtifactRepositories(), localRepository );
}
catch ( ArtifactResolutionException ex )
{
//shall be check before actually resolving from repos?
checkReactor( art, nbmArt );
if (!nbmArt.isResolved()) {
throw new MojoExecutionException( "Failed to retrieve the nbm file from repository", ex );
}
}
catch ( ArtifactNotFoundException ex )
{
//shall be check before actually resolving from repos?
checkReactor( art, nbmArt );
if (!nbmArt.isResolved()) {
throw new MojoExecutionException( "Failed to retrieve the nbm file from repository", ex );
}
}
return new ArtifactResult(nbmArt, mnf);
}
if ( mnf.isOsgiBundle() )
{
return new ArtifactResult(null, mnf);
}
}
return new ArtifactResult(null, null);
}
protected final class ArtifactResult {
private final Artifact converted;
private final ExamineManifest manifest;
ArtifactResult(Artifact conv, ExamineManifest manifest) {
converted = conv;
this.manifest = manifest;
}
boolean hasConvertedArtifact() {
return converted != null;
}
Artifact getConvertedArtifact() {
return converted;
}
public boolean isOSGiBundle() {
return manifest != null && manifest.isOsgiBundle();
}
public ExamineManifest getExaminedManifest() {
return manifest;
}
}
private void checkReactor( Artifact art, Artifact nbmArt )
{
if ( art.getFile().getName().endsWith( ".jar" ) )
{
String name = art.getFile().getName();
name = name.substring( 0, name.length() - ".jar".length() ) + ".nbm";
File fl = new File( art.getFile().getParentFile(), name );
if ( fl.exists() )
{
nbmArt.setFile( fl );
nbmArt.setResolved( true );
}
}
}
}