/*
* Copyright (c) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses>.
*/
package com.redhat.rcm.version.model;
import static com.redhat.rcm.version.util.PomUtils.cloneModel;
import java.io.File;
import java.util.Collections;
import java.util.List;
import org.apache.maven.mae.project.ProjectToolsException;
import org.apache.maven.mae.project.key.FullProjectKey;
import org.apache.maven.mae.project.key.VersionlessProjectKey;
import org.apache.maven.model.Build;
import org.apache.maven.model.BuildBase;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Extension;
import org.apache.maven.model.Model;
import org.apache.maven.model.ModelBase;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Profile;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.Reporting;
import org.apache.maven.model.building.ModelBuildingResult;
import com.redhat.rcm.version.VManException;
import com.redhat.rcm.version.mgr.mod.ProjectModder;
/**
* Provides a convenient way of passing around related information about a Maven
* project without passing multiple parameters. The models in this class
* represent two basic concepts: a model that is being modified by VMan, and
* other forms of that model used for comparison. Also stored is the key and
* original POM file related to these models.
*
* @author jdcasey
*/
public class Project
{
/**
* Original POM file from which this model information was loaded.
*/
private final File pom;
/**
* Model undergoing modification during VMan execution. This model is what
* will eventually be written back to disk.
*/
private final Model model;
/**
* Original (raw) model loaded from the POM file. This has NO interpolation,
* inheritance, or profile injection in it...it is literally the Model
* resulting from parsing the POM file.
*
* It is kept for comparison purposes ONLY.
*/
private final Model originalModel;
private FullProjectKey key;
/**
* In cases where comparison vs. the original, raw model isn't sufficient,
* this model instance MAY contain the full effective model resulting from
* loading the POM, its full ancestry, and its referenced BOMs, then injecting
* the profiles that are active by default.
*
* It is kept for reference ONLY.
*
* @see EffectiveModelBuilder#loadEffectiveModel(Project, com.redhat.rcm.version.mgr.session.VersionManagerSession)
*/
private Model effectiveModel;
public Project( final FullProjectKey key, final File pom, final Model model, final Model originalModel )
{
this.pom = pom;
this.model = model;
this.originalModel = originalModel;
this.key = key;
}
public Project( final FullProjectKey key, final File pom, final Model model )
throws VManException
{
this( key, pom, model, cloneModel( model ) );
}
public Project( final File pom, final Model model )
throws ProjectToolsException
{
this( new FullProjectKey( model ), pom, model, cloneModel( model ) );
}
public Project( final Model model )
throws ProjectToolsException
{
this( new FullProjectKey( model ), model.getPomFile(), model, cloneModel( model ) );
}
public Project( final Model raw, final ModelBuildingResult mbResult, final File pom )
throws ProjectToolsException
{
this.pom = pom;
this.originalModel = cloneModel( raw );
this.model = raw;
this.effectiveModel = mbResult.getEffectiveModel();
this.key = new FullProjectKey( raw );
}
public File getPom()
{
return pom;
}
public Model getModel()
{
return model;
}
public FullProjectKey getKey()
{
return key;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ( ( key == null ) ? 0 : key.hashCode() );
return result;
}
@Override
public boolean equals( final Object obj )
{
if ( this == obj )
{
return true;
}
if ( obj == null )
{
return false;
}
if ( getClass() != obj.getClass() )
{
return false;
}
final Project other = (Project) obj;
if ( key == null )
{
if ( other.key != null )
{
return false;
}
}
else if ( !key.equals( other.key ) )
{
return false;
}
return true;
}
@Override
public String toString()
{
return key + " [pom=" + pom + "]";
}
public Parent getParent()
{
return model.getParent();
}
public String getGroupId()
{
return key.getGroupId();
}
public String getArtifactId()
{
return key.getArtifactId();
}
public String getVersion()
{
return key.getVersion();
}
public List<Plugin> getPlugins()
{
return getPlugins( model );
}
public List<Plugin> getPlugins( final ModelBase base )
{
final BuildBase build = getBuild( base );
if ( build == null )
{
return Collections.emptyList();
}
final List<Plugin> result = build.getPlugins();
if ( result == null )
{
return Collections.emptyList();
}
return result;
}
public Build getBuild()
{
return (Build) getBuild( model );
}
public BuildBase getBuild( final ModelBase base )
{
BuildBase build = null;
if ( base instanceof Model )
{
build = ( (Model) base ).getBuild();
}
else
{
build = ( (Profile) base ).getBuild();
}
return build;
}
public List<Plugin> getManagedPlugins()
{
return getManagedPlugins( model );
}
public List<Plugin> getManagedPlugins( final ModelBase base )
{
if ( base instanceof Model )
{
final Build build = ( (Model) base ).getBuild();
if ( build == null )
{
return Collections.emptyList();
}
final PluginManagement pm = build.getPluginManagement();
if ( pm == null )
{
return Collections.emptyList();
}
final List<Plugin> result = pm.getPlugins();
if ( result == null )
{
return Collections.emptyList();
}
return result;
}
return Collections.emptyList();
}
public List<ReportPlugin> getReportPlugins()
{
return getReportPlugins( model );
}
public List<ReportPlugin> getReportPlugins( final ModelBase base )
{
final Reporting reporting = base.getReporting();
if ( reporting == null )
{
return Collections.emptyList();
}
return reporting.getPlugins();
}
public Iterable<Dependency> getDependencies()
{
return getDependencies( model );
}
public Iterable<Dependency> getDependencies( final ModelBase base )
{
List<Dependency> deps = base.getDependencies();
if ( deps == null )
{
deps = Collections.emptyList();
}
return deps;
}
public Iterable<Dependency> getManagedDependencies()
{
return getManagedDependencies( model );
}
public Iterable<Dependency> getManagedDependencies( final ModelBase base )
{
final DependencyManagement dm = base.getDependencyManagement();
if ( dm == null || dm.getDependencies() == null )
{
return Collections.emptyList();
}
return dm.getDependencies();
}
/**
* In the event the groupId or version changes in the model being modified
* (represented by this Project instance), this method will update the stored
* key with the new coordinate information.
*
* This can be important if the model doesn't specify a groupId and its
* parent reference is relocated (which will result in this project's
* groupId changing, since it's inherited under these circumstances).
*
* @throws ProjectToolsException If the new coordinate's version doesn't parse.
*/
public void updateCoord()
throws ProjectToolsException
{
try
{
key = new FullProjectKey( model );
}
catch ( final ProjectToolsException e )
{
throw new ProjectToolsException( "Failed to update project coordinate: %s", e, e.getMessage() );
}
}
/**
* In cases where plugin configuration has been injected or removed, this
* method will update the map of plugin keys to plugin instances within the
* modified {@link Model} instance itself to reflect the changes.
*
* This may be necessary to make the updates available to other
* {@link ProjectModder} instances that will run after the one making the
* change.
*/
public void flushPluginMaps()
{
flushPluginMaps( model );
final List<Profile> profiles = model.getProfiles();
if ( profiles != null )
{
for ( final Profile profile : profiles )
{
flushPluginMaps( profile );
}
}
}
public void flushPluginMaps( final ModelBase base )
{
final BuildBase build = getBuild( base );
if ( build != null )
{
build.flushPluginMap();
final PluginManagement pm = build.getPluginManagement();
if ( pm != null )
{
pm.flushPluginMap();
}
}
final Reporting reporting = model.getReporting();
if ( reporting != null )
{
reporting.flushReportPluginMap();
}
}
/**
* Set the effective model related to this project, which has inheritance
* and profile/BOM injection applied.
*
* @see EffectiveModelBuilder#loadEffectiveModel(Project, com.redhat.rcm.version.mgr.session.VersionManagerSession)
*/
public void setEffectiveModel( final Model effModel )
{
this.effectiveModel = effModel;
}
/**
* FOR REFERENCE ONLY.
*
* If set, return the effective {@link Model} instance.
*
* This model has had interpolation, inheritance, and profile/BOM
* injection calculated.
*
* @see EffectiveModelBuilder#loadEffectiveModel(Project, com.redhat.rcm.version.mgr.session.VersionManagerSession)
*/
public Model getEffectiveModel()
{
return effectiveModel;
}
/**
* FOR REFERENCE ONLY.
*
* Return the original {@link Model} instance AS IT WAS PARSED FROM THE POM.
* This is the RAW POM, without interpolation, inheritance, or profile
* injection calculated.
*/
public Model getOriginalModel()
{
return originalModel;
}
public VersionlessProjectKey getVersionlessParentKey()
{
return getParent() != null ? new VersionlessProjectKey( getParent() ) : null;
}
public List<Extension> getExtensions()
{
if ( model.getBuild() == null )
{
return Collections.emptyList();
}
final List<Extension> extensions = model.getBuild()
.getExtensions();
if ( extensions == null )
{
return Collections.emptyList();
}
return extensions;
}
public String getPackaging()
{
return model.getPackaging();
}
public VersionlessProjectKey getVersionlessKey()
{
return new VersionlessProjectKey( key );
}
}