View Javadoc

1   package org.apache.maven.plugin.war.overlay;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.List;
25  import java.util.ListIterator;
26  import java.util.Set;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
30  import org.apache.maven.plugin.war.Overlay;
31  import org.apache.maven.project.MavenProject;
32  import org.codehaus.plexus.util.StringUtils;
33  
34  /**
35   * Manages the overlays.
36   *
37   * @author Stephane Nicoll
38   * 
39   * @version $Id: OverlayManager.java 1390145 2012-09-25 21:13:36Z dennisl $
40   */
41  public class OverlayManager
42  {
43      private final List<Overlay> overlays;
44  
45      private final MavenProject project;
46  
47      private final List<Artifact> artifactsOverlays;
48  
49      /**
50       * Creates a manager with the specified overlays.
51       * <p/>
52       * Note that the list is potentially updated by the
53       * manager so a new list is created based on the overlays.
54       *
55       * @param overlays        the overlays
56       * @param project         the maven project
57       * @param defaultIncludes the default includes to use
58       * @param defaultExcludes the default excludes to use
59       * @param currentProjectOverlay the overlay for the current project
60       * @throws InvalidOverlayConfigurationException
61       *          if the config is invalid
62       */
63      public OverlayManager( List<Overlay> overlays, MavenProject project, String defaultIncludes, String defaultExcludes,
64                             Overlay currentProjectOverlay )
65          throws InvalidOverlayConfigurationException
66      {
67          this.overlays = new ArrayList<Overlay>();
68          if ( overlays != null )
69          {
70              this.overlays.addAll( overlays );
71          }
72          this.project = project;
73  
74          this.artifactsOverlays = getOverlaysAsArtifacts();
75  
76          // Initialize
77          initialize( defaultIncludes, defaultExcludes, currentProjectOverlay );
78  
79      }
80  
81  
82      /**
83       * Returns the resolved overlays.
84       *
85       * @return the overlays
86       */
87      public List<Overlay> getOverlays()
88      {
89          return overlays;
90      }
91  
92      /**
93       * Returns the id of the resolved overlays.
94       *
95       * @return the overlay ids
96       */
97      public List<String> getOverlayIds()
98      {
99          final List<String> result = new ArrayList<String>();
100         for ( Overlay overlay : overlays )
101         {
102             result.add( overlay.getId() );
103         }
104         return result;
105 
106     }
107 
108     /**
109      * Initializes the manager and validates the overlays configuration.
110      *
111      * @param defaultIncludes the default includes to use
112      * @param defaultExcludes the default excludes to use
113      * @param currentProjectOverlay  the overlay for the current project
114      * @throws InvalidOverlayConfigurationException
115      *          if the configuration is invalid
116      */
117     void initialize( String defaultIncludes, String defaultExcludes, Overlay currentProjectOverlay )
118         throws InvalidOverlayConfigurationException
119     {
120 
121         // Build the list of configured artifacts and makes sure that each overlay
122         // refer to a valid artifact
123         final List<Artifact> configuredWarArtifacts = new ArrayList<Artifact>();
124         final ListIterator<Overlay> it = overlays.listIterator();
125         while ( it.hasNext() )
126         {
127             Overlay overlay = (Overlay) it.next();
128             if ( overlay == null )
129             {
130                 throw new InvalidOverlayConfigurationException( "overlay could not be null." );
131             }
132             // If it's the current project, return the project instance
133             if ( overlay.isCurrentProject() )
134             {
135                 overlay = currentProjectOverlay;
136                 it.set( overlay );
137             }
138             // default includes/excludes - only if the overlay uses the default settings
139             if ( Arrays.equals( Overlay.DEFAULT_INCLUDES, overlay.getIncludes() )
140                 && Arrays.equals( Overlay.DEFAULT_EXCLUDES, overlay.getExcludes() ) )
141             {
142                 overlay.setIncludes( defaultIncludes );
143                 overlay.setExcludes( defaultExcludes );
144             }
145 
146             final Artifact artifact = getAssociatedArtifact( overlay );
147             if ( artifact != null )
148             {
149                 configuredWarArtifacts.add( artifact );
150                 overlay.setArtifact( artifact );
151             }
152         }
153 
154         // Build the list of missing overlays
155         for ( Artifact artifact : artifactsOverlays )
156         {
157             if ( !configuredWarArtifacts.contains( artifact ) )
158             {
159                 // Add a default overlay for the given artifact which will be applied after
160                 // the ones that have been configured
161                 overlays.add( new DefaultOverlay( artifact, defaultIncludes, defaultExcludes ) );
162             }
163         }
164 
165         // Final validation, make sure that the current project is in there. Otherwise add it first
166         for ( Overlay overlay : overlays )
167         {
168             if ( overlay.equals( currentProjectOverlay ) )
169             {
170                 return;
171             }
172         }
173         overlays.add( 0, currentProjectOverlay );
174     }
175 
176     /**
177      * Returns the Artifact associated to the specified overlay.
178      * <p/>
179      * If the overlay defines the current project, <tt>null</tt> is
180      * returned. If no artifact could not be found for the overlay
181      * a InvalidOverlayConfigurationException is thrown.
182      *
183      * @param overlay an overlay
184      * @return the artifact associated to the overlay
185      * @throws org.apache.maven.plugin.war.overlay.InvalidOverlayConfigurationException
186      *          if the overlay does not have an associated artifact
187      */
188     Artifact getAssociatedArtifact( final Overlay overlay )
189         throws InvalidOverlayConfigurationException
190     {
191         if ( overlay.isCurrentProject() )
192         {
193             return null;
194         }
195 
196         for ( Artifact artifact : artifactsOverlays )
197         {
198             // Handle classifier dependencies properly (clash management)
199             if ( compareOverlayWithArtifact( overlay, artifact ) )
200             {
201                 return artifact;
202             }
203         }
204 
205         // maybe its a project dependencies zip or an other type
206         @SuppressWarnings( "unchecked" )
207         Set<Artifact> projectArtifacts = this.project.getDependencyArtifacts();
208         if ( projectArtifacts != null )
209         {
210             for ( Artifact artifact : projectArtifacts )
211             {
212                 if ( compareOverlayWithArtifact( overlay, artifact ) )
213                 {
214                     return artifact;
215                 }
216             }
217         }
218         throw new InvalidOverlayConfigurationException(
219             "overlay [" + overlay + "] is not a dependency of the project." );
220 
221     }
222 
223     /**
224      * Compare groupId && artifactId && type && classifier.
225      *
226      * @param overlay the overlay
227      * @param artifact the artifact
228      * @return boolean true if equals
229      */
230     private boolean compareOverlayWithArtifact( Overlay overlay, Artifact artifact )
231     {
232         return ( StringUtils.equals( overlay.getGroupId(), artifact.getGroupId() )
233             && StringUtils.equals( overlay.getArtifactId(), artifact.getArtifactId() )
234             && StringUtils.equals( overlay.getType(), artifact.getType() )
235             // MWAR-241 Make sure to treat null and "" as equal when comparing the classifier
236             && StringUtils.equals( StringUtils.defaultString( overlay.getClassifier() ), StringUtils.defaultString( artifact.getClassifier() ) ) );
237     }
238 
239     /**
240      * Returns a list of WAR {@link org.apache.maven.artifact.Artifact} describing
241      * the overlays of the current project.
242      *
243      * @return the overlays as artifacts objects
244      */
245     private List<Artifact> getOverlaysAsArtifacts()
246     {
247         ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
248         @SuppressWarnings( "unchecked" )
249         final Set<Artifact> artifacts = project.getArtifacts();
250 
251         final List<Artifact> result = new ArrayList<Artifact>();
252         for ( Artifact artifact : artifacts )
253         {
254             if ( !artifact.isOptional() && filter.include( artifact ) && ( "war".equals( artifact.getType() ) ) )
255             {
256                 result.add( artifact );
257             }
258         }
259         return result;
260     }
261 }