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 org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
24 import org.apache.maven.plugin.war.Overlay;
25 import org.apache.maven.project.MavenProject;
26 import org.codehaus.plexus.util.StringUtils;
27
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.ListIterator;
33 import java.util.Set;
34
35 /**
36 * Manages the overlays.
37 *
38 * @author Stephane Nicoll
39 *
40 * @version $Id: OverlayManager.java 985595 2010-08-14 22:29:50Z dennisl $
41 */
42 public class OverlayManager
43 {
44 private final List overlays;
45
46 private final MavenProject project;
47
48 private final List artifactsOverlays;
49
50 /**
51 * Creates a manager with the specified overlays.
52 * <p/>
53 * Note that the list is potentially updated by the
54 * manager so a new list is created based on the overlays.
55 *
56 * @param overlays the overlays
57 * @param project the maven project
58 * @param defaultIncludes the default includes to use
59 * @param defaultExcludes the default excludes to use
60 * @param currentProjectOverlay the overlay for the current project
61 * @throws InvalidOverlayConfigurationException
62 * if the config is invalid
63 */
64 public OverlayManager( List overlays, MavenProject project, String defaultIncludes, String defaultExcludes,
65 Overlay currentProjectOverlay )
66 throws InvalidOverlayConfigurationException
67 {
68 this.overlays = new ArrayList();
69 if ( overlays != null )
70 {
71 this.overlays.addAll( overlays );
72 }
73 this.project = project;
74
75 this.artifactsOverlays = getOverlaysAsArtifacts();
76
77 // Initialize
78 initialize( defaultIncludes, defaultExcludes, currentProjectOverlay );
79
80 }
81
82
83 /**
84 * Returns the resolved overlays.
85 *
86 * @return the overlays
87 */
88 public List getOverlays()
89 {
90 return overlays;
91 }
92
93 /**
94 * Returns the id of the resolved overlays.
95 *
96 * @return the overlay ids
97 */
98 public List getOverlayIds()
99 {
100 final Iterator it = overlays.iterator();
101 final List result = new ArrayList();
102 while ( it.hasNext() )
103 {
104 Overlay overlay = (Overlay) it.next();
105 result.add( overlay.getId() );
106 }
107 return result;
108
109 }
110
111 /**
112 * Intializes the manager and validates the overlays configuration.
113 *
114 * @param defaultIncludes the default includes to use
115 * @param defaultExcludes the default excludes to use
116 * @param currentProjectOverlay the overlay for the current project
117 * @throws InvalidOverlayConfigurationException
118 * if the configuration is invalid
119 */
120 void initialize( String defaultIncludes, String defaultExcludes, Overlay currentProjectOverlay )
121 throws InvalidOverlayConfigurationException
122 {
123
124 // Build the list of configured artifacts and makes sure that each overlay
125 // refer to a valid artifact
126 final List configuredWarArtifacts = new ArrayList();
127 final ListIterator it = overlays.listIterator();
128 while ( it.hasNext() )
129 {
130 Overlay overlay = (Overlay) it.next();
131 if ( overlay == null )
132 {
133 throw new InvalidOverlayConfigurationException( "overlay could not be null." );
134 }
135 // If it's the current project, return the project instance
136 if ( overlay.isCurrentProject() )
137 {
138 overlay = currentProjectOverlay;
139 it.set( overlay );
140 }
141 // default includes/excludes - only if the overlay uses the default settings
142 if ( Arrays.equals( Overlay.DEFAULT_INCLUDES, overlay.getIncludes() )
143 && Arrays.equals( Overlay.DEFAULT_EXCLUDES, overlay.getExcludes() ) )
144 {
145 overlay.setIncludes( defaultIncludes );
146 overlay.setExcludes( defaultExcludes );
147 }
148
149 final Artifact artifact = getAssociatedArtifact( overlay );
150 if ( artifact != null )
151 {
152 configuredWarArtifacts.add( artifact );
153 overlay.setArtifact( artifact );
154 }
155 }
156
157 // Build the list of missing overlays
158 final Iterator it2 = artifactsOverlays.iterator();
159 while ( it2.hasNext() )
160 {
161 Artifact artifact = (Artifact) it2.next();
162 if ( !configuredWarArtifacts.contains( artifact ) )
163 {
164 // Add a default overlay for the given artifact which will be applied after
165 // the ones that have been configured
166 overlays.add( new DefaultOverlay( artifact, defaultIncludes, defaultExcludes ) );
167 }
168 }
169
170 // Final validation, make sure that the current project is in there. Otherwise add it first
171 final Iterator it3 = overlays.iterator();
172 while ( it3.hasNext() )
173 {
174 Overlay overlay = (Overlay) it3.next();
175 if ( overlay.equals( currentProjectOverlay ) )
176 {
177 return;
178 }
179 }
180 overlays.add( 0, currentProjectOverlay );
181 }
182
183 /**
184 * Returns the Artifact associated to the specified overlay.
185 * <p/>
186 * If the overlay defines the current project, <tt>null</tt> is
187 * returned. If no artifact could not be found for the overlay
188 * a InvalidOverlayConfigurationException is thrown.
189 *
190 * @param overlay an overlay
191 * @return the artifact associated to the overlay
192 * @throws org.apache.maven.plugin.war.overlay.InvalidOverlayConfigurationException
193 * if the overlay does not have an associated artifact
194 */
195 Artifact getAssociatedArtifact( final Overlay overlay )
196 throws InvalidOverlayConfigurationException
197 {
198 if ( overlay.isCurrentProject() )
199 {
200 return null;
201 }
202
203 for ( Iterator iterator = artifactsOverlays.iterator(); iterator.hasNext(); )
204 {
205 // Handle classifier dependencies properly (clash management)
206 Artifact artifact = (Artifact) iterator.next();
207 if ( compareOverlayWithArtifact( overlay, artifact ) )
208 {
209 return artifact;
210 }
211 }
212
213 // maybe its a project dependencies zip or an other type
214 Set projectArtifacts = this.project.getDependencyArtifacts();
215 if ( projectArtifacts != null )
216 {
217 for ( Iterator iterator = projectArtifacts.iterator(); iterator.hasNext(); )
218 {
219 Artifact artifact = (Artifact) iterator.next();
220 if ( compareOverlayWithArtifact( overlay, artifact ) )
221 {
222 return artifact;
223 }
224 }
225 }
226 throw new InvalidOverlayConfigurationException(
227 "overlay [" + overlay + "] is not a dependency of the project." );
228
229 }
230
231 /**
232 * compare groupId && artifactId && Type && classifier
233 * @param overlay the overlay
234 * @param artifact the artifact
235 * @return boolean true if equals
236 */
237 private boolean compareOverlayWithArtifact( Overlay overlay, Artifact artifact )
238 {
239 return ( StringUtils.equals( overlay.getGroupId(), artifact.getGroupId() )
240 && StringUtils.equals( overlay.getArtifactId(), artifact.getArtifactId() )
241 && StringUtils.equals( overlay.getType(), artifact.getType() )
242 && StringUtils.equals( overlay.getClassifier(), artifact.getClassifier() ) );
243 }
244
245 /**
246 * Returns a list of WAR {@link org.apache.maven.artifact.Artifact} describing
247 * the overlays of the current project.
248 *
249 * @return the overlays as artifacts objects
250 */
251 private List getOverlaysAsArtifacts()
252 {
253 ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
254 final Set artifacts = project.getArtifacts();
255 final Iterator it = artifacts.iterator();
256
257 final List result = new ArrayList();
258 while ( it.hasNext() )
259 {
260 Artifact artifact = (Artifact) it.next();
261 if ( !artifact.isOptional() && filter.include( artifact ) && ( "war".equals( artifact.getType() ) ) )
262 {
263 result.add( artifact );
264 }
265 }
266 return result;
267 }
268 }