1 package org.apache.maven.plugins.ear;
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.Set;
23
24 import org.apache.maven.artifact.Artifact;
25 import org.apache.maven.plugin.MojoFailureException;
26 import org.apache.maven.plugins.ear.util.ArtifactRepository;
27 import org.apache.maven.shared.mapping.MappingUtils;
28 import org.codehaus.plexus.interpolation.InterpolationException;
29 import org.codehaus.plexus.util.xml.XMLWriter;
30
31 /**
32 * A base implementation of an {@link EarModule}.
33 *
34 * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
35 */
36 public abstract class AbstractEarModule
37 implements EarModule
38 {
39
40 /**
41 * The module element.
42 */
43 protected static final String MODULE_ELEMENT = "module";
44
45 /**
46 * The java module.
47 */
48 protected static final String JAVA_MODULE = "java";
49
50 /**
51 * The alt-dd module.
52 */
53 protected static final String ALT_DD = "alt-dd";
54
55 private Artifact artifact;
56
57 // Those are set by the configuration
58
59 private String groupId;
60
61 private String artifactId;
62
63 private String classifier;
64
65 /**
66 * The bundleDir.
67 */
68 protected String bundleDir;
69
70 /**
71 * The bundleFileName.
72 */
73 protected String bundleFileName;
74
75 /**
76 * excluded by default {@code false}.
77 */
78 protected Boolean excluded = Boolean.FALSE;
79
80 private String uri;
81
82 /**
83 * unpack
84 */
85 protected Boolean unpack = null;
86
87 /**
88 * The alternate deployment descriptor.
89 */
90 protected String altDeploymentDescriptor;
91
92 private String moduleId;
93
94 // This is injected once the module has been built.
95
96 /**
97 * The {@link EarExecutionContext}
98 */
99 protected EarExecutionContext earExecutionContext;
100
101 /**
102 * Empty constructor to be used when the module is built based on the configuration.
103 */
104 public AbstractEarModule()
105 {
106 }
107
108 /**
109 * Creates an ear module from the artifact.
110 *
111 * @param a the artifact
112 */
113 public AbstractEarModule( Artifact a )
114 {
115 this.artifact = a;
116 this.groupId = a.getGroupId();
117 this.artifactId = a.getArtifactId();
118 this.classifier = a.getClassifier();
119 this.bundleDir = null;
120 }
121
122 /**
123 * {@inheritDoc}
124 */
125 public void setEarExecutionContext( EarExecutionContext earExecutionContext )
126 {
127 this.earExecutionContext = earExecutionContext;
128 }
129
130 /** {@inheritDoc} */
131 public void resolveArtifact( Set<Artifact> artifacts )
132 throws EarPluginException, MojoFailureException
133 {
134 // If the artifact is already set no need to resolve it
135 if ( artifact == null )
136 {
137 // Make sure that at least the groupId and the artifactId are specified
138 if ( groupId == null || artifactId == null )
139 {
140 throw new MojoFailureException( "Could not resolve artifact[" + groupId + ":" + artifactId + ":"
141 + getType() + "]" );
142 }
143 final ArtifactRepository ar = earExecutionContext.getArtifactRepository();
144 artifact = ar.getUniqueArtifact( groupId, artifactId, getType(), classifier );
145 // Artifact has not been found
146 if ( artifact == null )
147 {
148 Set<Artifact> candidates = ar.getArtifacts( groupId, artifactId, getType() );
149 if ( candidates.size() > 1 )
150 {
151 throw new MojoFailureException( "Artifact[" + this + "] has " + candidates.size()
152 + " candidates, please provide a classifier." );
153 }
154 else
155 {
156 throw new MojoFailureException( "Artifact[" + this + "] is not a dependency of the project." );
157 }
158 }
159 }
160 }
161
162 /**
163 * @return {@link #artifact}
164 */
165 public Artifact getArtifact()
166 {
167 return artifact;
168 }
169
170 /**
171 * @return {@link #moduleId}
172 */
173 public String getModuleId()
174 {
175 return moduleId;
176 }
177
178 /**
179 * @return Return the URI.
180 */
181 public String getUri()
182 {
183 if ( uri == null )
184 {
185 if ( getBundleDir() == null )
186 {
187 uri = getBundleFileName();
188 }
189 else
190 {
191 uri = getBundleDir() + getBundleFileName();
192 }
193 }
194 return uri;
195 }
196
197 /**
198 * Returns the artifact's groupId.
199 *
200 * @return {@link #groupId}
201 */
202 public String getGroupId()
203 {
204 return groupId;
205 }
206
207 /**
208 * Returns the artifact's Id.
209 *
210 * @return {@link #artifactId}
211 */
212 public String getArtifactId()
213 {
214 return artifactId;
215 }
216
217 /**
218 * Returns the artifact's classifier.
219 *
220 * @return the artifact classifier
221 */
222 public String getClassifier()
223 {
224 return classifier;
225 }
226
227 /**
228 * Returns the bundle directory. If null, the module is bundled in the root of the EAR.
229 *
230 * @return the custom bundle directory
231 */
232 public String getBundleDir()
233 {
234 if ( bundleDir != null )
235 {
236 bundleDir = cleanBundleDir( bundleDir );
237 }
238 return bundleDir;
239 }
240
241 /**
242 * Returns the bundle file name. If null, the artifact's file name is returned.
243 *
244 * @return the bundle file name
245 */
246 public String getBundleFileName()
247 {
248 if ( bundleFileName == null )
249 {
250 try
251 {
252 String outputFileNameMapping = earExecutionContext.getOutputFileNameMapping();
253 bundleFileName = MappingUtils.evaluateFileNameMapping( outputFileNameMapping, artifact );
254 }
255 catch ( InterpolationException e )
256 {
257 // We currently ignore this here, cause assumption is that
258 // has already been happened before..
259 // FIXME: Should be checked first.
260 }
261
262 // bundleFileName = earExecutionContext.getFileNameMapping().mapFileName( artifact );
263 }
264 return bundleFileName;
265 }
266
267 /**
268 * The alt-dd element specifies an optional URI to the post-assembly version of the deployment descriptor file for a
269 * particular Java EE module. The URI must specify the full pathname of the deployment descriptor file relative to
270 * the application's root directory.
271 *
272 * @return the alternative deployment descriptor for this module
273 */
274 public String getAltDeploymentDescriptor()
275 {
276 return altDeploymentDescriptor;
277 }
278
279 /**
280 * Specify whether this module should be excluded or not.
281 *
282 * @return true if this module should be skipped, false otherwise
283 */
284 public boolean isExcluded()
285 {
286 return excluded;
287 }
288
289 /**
290 * @return {@link #unpack}
291 */
292 public Boolean shouldUnpack()
293 {
294 return unpack;
295 }
296
297 /**
298 * Writes the alternative deployment descriptor if necessary.
299 *
300 * @param writer the writer to use
301 * @param version the java EE version in use
302 */
303 protected void writeAltDeploymentDescriptor( XMLWriter writer, String version )
304 {
305 if ( getAltDeploymentDescriptor() != null )
306 {
307 writer.startElement( ALT_DD );
308 writer.writeText( getAltDeploymentDescriptor() );
309 writer.endElement();
310 }
311 }
312
313 /**
314 * Starts a new {@link #MODULE_ELEMENT} on the specified writer, possibly including an id attribute.
315 *
316 * @param writer the XML writer.
317 * @param generateId whether an id should be generated
318 */
319 protected void startModuleElement( XMLWriter writer, Boolean generateId )
320 {
321 writer.startElement( MODULE_ELEMENT );
322
323 // If a moduleId is specified, always include it
324 if ( getModuleId() != null )
325 {
326 writer.addAttribute( "id", getModuleId() );
327 }
328 else if ( generateId )
329 {
330 // No module id was specified but one should be generated.
331 // FIXME: Should we use the mapping using outputFileNameMapping instead
332 // of doing this on our own?
333 Artifact theArtifact = getArtifact();
334 String generatedId = theArtifact.getType().toUpperCase() + "_" + theArtifact.getGroupId() + "."
335 + theArtifact.getArtifactId();
336 if ( null != theArtifact.getClassifier() && theArtifact.getClassifier().trim().length() > 0 )
337 {
338 generatedId += "-" + theArtifact.getClassifier().trim();
339 }
340 writer.addAttribute( "id", generatedId );
341 }
342 }
343
344 /**
345 * {@inheritDoc}
346 */
347 public String toString()
348 {
349 StringBuilder sb = new StringBuilder();
350 sb.append( getType() ).append( ":" ).append( groupId ).append( ":" ).append( artifactId );
351 if ( classifier != null )
352 {
353 sb.append( ":" ).append( classifier );
354 }
355 if ( artifact != null )
356 {
357 sb.append( ":" ).append( artifact.getVersion() );
358 }
359 return sb.toString();
360 }
361
362 /**
363 * Cleans the bundle directory so that it might be used properly.
364 *
365 * @param bundleDir the bundle directory to clean
366 * @return the cleaned bundle directory
367 */
368 static String cleanBundleDir( String bundleDir )
369 {
370 if ( bundleDir == null )
371 {
372 return null;
373 }
374
375 // Using slashes
376 bundleDir = bundleDir.replace( '\\', '/' );
377
378 // Remove '/' prefix if any so that directory is a relative path
379 if ( bundleDir.startsWith( "/" ) )
380 {
381 bundleDir = bundleDir.substring( 1, bundleDir.length() );
382 }
383
384 if ( bundleDir.length() > 0 && !bundleDir.endsWith( "/" ) )
385 {
386 // Adding '/' suffix to specify a directory structure if it is not empty
387 bundleDir = bundleDir + "/";
388 }
389
390 return bundleDir;
391 }
392
393 /**
394 * Specify if the objects are both null or both equal.
395 *
396 * @param first the first object
397 * @param second the second object
398 * @return true if parameters are either both null or equal
399 */
400 static boolean areNullOrEqual( Object first, Object second )
401 {
402 if ( first != null )
403 {
404 return first.equals( second );
405 }
406 else
407 {
408 return second == null;
409 }
410 }
411
412 /**
413 * Sets the URI of the module explicitly for testing purposes.
414 *
415 * @param uri the uri
416 */
417 void setUri( String uri )
418 {
419 this.uri = uri;
420
421 }
422
423 /**
424 * @return always {@code true}
425 */
426 public boolean changeManifestClasspath()
427 {
428 return true;
429 }
430
431 /**
432 * @return always {@code null}
433 */
434 public String getLibDir()
435 {
436 return null;
437 }
438 }