blob: c455dbe59974e0a0dff7e75b0bb4f8da2200926d [file] [log] [blame]
package org.apache.maven.plugins.war.overlay;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugins.war.Overlay;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.StringUtils;
/**
* Manages the overlays.
*
* @author Stephane Nicoll
* @version $Id$
*/
public class OverlayManager
{
private final List<Overlay> overlays;
private final MavenProject project;
private final List<Artifact> artifactsOverlays;
/**
* Creates a manager with the specified overlays.
*
* Note that the list is potentially updated by the manager so a new list is created based on the overlays.
*
* @param overlays the overlays
* @param project the maven project
* @param defaultIncludes the default includes to use
* @param defaultExcludes the default excludes to use
* @param currentProjectOverlay the overlay for the current project
* @throws InvalidOverlayConfigurationException if the config is invalid
*/
public OverlayManager( List<Overlay> overlays, MavenProject project, String[] defaultIncludes,
String[] defaultExcludes, Overlay currentProjectOverlay )
throws InvalidOverlayConfigurationException
{
this.overlays = new ArrayList<Overlay>();
if ( overlays != null )
{
this.overlays.addAll( overlays );
}
this.project = project;
this.artifactsOverlays = getOverlaysAsArtifacts();
// Initialize
initialize( defaultIncludes, defaultExcludes, currentProjectOverlay );
}
/**
* Returns the resolved overlays.
*
* @return the overlays
*/
public List<Overlay> getOverlays()
{
return overlays;
}
/**
* Returns the id of the resolved overlays.
*
* @return the overlay ids
*/
public List<String> getOverlayIds()
{
final List<String> result = new ArrayList<String>();
for ( Overlay overlay : overlays )
{
result.add( overlay.getId() );
}
return result;
}
/**
* Initializes the manager and validates the overlays configuration.
*
* @param defaultIncludes the default includes to use
* @param defaultExcludes the default excludes to use
* @param currentProjectOverlay the overlay for the current project
* @throws InvalidOverlayConfigurationException if the configuration is invalid
*/
void initialize( String[] defaultIncludes, String[] defaultExcludes, Overlay currentProjectOverlay )
throws InvalidOverlayConfigurationException
{
// Build the list of configured artifacts and makes sure that each overlay
// refer to a valid artifact
final List<Artifact> configuredWarArtifacts = new ArrayList<Artifact>();
final ListIterator<Overlay> it = overlays.listIterator();
while ( it.hasNext() )
{
Overlay overlay = it.next();
if ( overlay == null )
{
throw new InvalidOverlayConfigurationException( "overlay could not be null." );
}
// If it's the current project, return the project instance
if ( overlay.isCurrentProject() )
{
overlay = currentProjectOverlay;
it.set( overlay );
}
// default includes/excludes - only if the overlay uses the default settings
if ( Arrays.equals( Overlay.DEFAULT_INCLUDES, overlay.getIncludes() )
&& Arrays.equals( Overlay.DEFAULT_EXCLUDES, overlay.getExcludes() ) )
{
overlay.setIncludes( defaultIncludes );
overlay.setExcludes( defaultExcludes );
}
final Artifact artifact = getAssociatedArtifact( overlay );
if ( artifact != null )
{
configuredWarArtifacts.add( artifact );
overlay.setArtifact( artifact );
}
}
// Build the list of missing overlays
for ( Artifact artifact : artifactsOverlays )
{
if ( !configuredWarArtifacts.contains( artifact ) )
{
// Add a default overlay for the given artifact which will be applied after
// the ones that have been configured
overlays.add( new DefaultOverlay( artifact, defaultIncludes, defaultExcludes ) );
}
}
// Final validation, make sure that the current project is in there. Otherwise add it first
for ( Overlay overlay : overlays )
{
if ( overlay.equals( currentProjectOverlay ) )
{
return;
}
}
overlays.add( 0, currentProjectOverlay );
}
/**
* Returns the Artifact associated to the specified overlay.
*
* If the overlay defines the current project, <tt>null</tt> is returned. If no artifact could not be found for the
* overlay a InvalidOverlayConfigurationException is thrown.
*
* @param overlay an overlay
* @return the artifact associated to the overlay
* @throws org.apache.maven.plugins.war.overlay.InvalidOverlayConfigurationException if the overlay does not have an
* associated artifact
*/
Artifact getAssociatedArtifact( final Overlay overlay )
throws InvalidOverlayConfigurationException
{
if ( overlay.isCurrentProject() )
{
return null;
}
for ( Artifact artifact : artifactsOverlays )
{
// Handle classifier dependencies properly (clash management)
if ( compareOverlayWithArtifact( overlay, artifact ) )
{
return artifact;
}
}
// maybe its a project dependencies zip or an other type
Set<Artifact> projectArtifacts = this.project.getDependencyArtifacts();
if ( projectArtifacts != null )
{
for ( Artifact artifact : projectArtifacts )
{
if ( compareOverlayWithArtifact( overlay, artifact ) )
{
return artifact;
}
}
}
// CHECKSTYLE_OFF: LineLength
throw new InvalidOverlayConfigurationException( "overlay [" + overlay + "] is not a dependency of the project." );
// CHECKSTYLE_ON: LineLength
}
/**
* Compare groupId && artifactId && type && classifier.
*
* @param overlay the overlay
* @param artifact the artifact
* @return boolean true if equals
*/
private boolean compareOverlayWithArtifact( Overlay overlay, Artifact artifact )
{
return ( StringUtils.equals( overlay.getGroupId(), artifact.getGroupId() )
&& StringUtils.equals( overlay.getArtifactId(), artifact.getArtifactId() )
&& StringUtils.equals( overlay.getType(), artifact.getType() )
// MWAR-241 Make sure to treat null and "" as equal when comparing the classifier
&& StringUtils.equals( StringUtils.defaultString( overlay.getClassifier() ),
StringUtils.defaultString( artifact.getClassifier() ) ) );
}
/**
* Returns a list of WAR {@link org.apache.maven.artifact.Artifact} describing the overlays of the current project.
*
* @return the overlays as artifacts objects
*/
private List<Artifact> getOverlaysAsArtifacts()
{
ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
final Set<Artifact> artifacts = project.getArtifacts();
final List<Artifact> result = new ArrayList<Artifact>();
for ( Artifact artifact : artifacts )
{
if ( !artifact.isOptional() && filter.include( artifact ) && ( "war".equals( artifact.getType() ) ) )
{
result.add( artifact );
}
}
return result;
}
}