1 package org.apache.maven.plugin.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.plugin.ear.output.FileNameMappingFactory;
27 import org.apache.maven.plugin.ear.util.ArtifactRepository;
28 import org.codehaus.plexus.util.xml.XMLWriter;
29
30 /**
31 * A base implementation of an {@link EarModule}.
32 *
33 * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
34 * @version $Id: AbstractEarModule.java 1645331 2014-12-13 17:31:09Z khmarbaise $
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 bundleFileName = earExecutionContext.getFileNameMapping().mapFileName( artifact );
251 }
252 return bundleFileName;
253 }
254
255 /**
256 * Based on MEAR-189 we need to get back
257 * the original file name under any circumstances.
258 *
259 * @return The original file name.
260 */
261 public String getOriginalBundleFileName()
262 {
263 return FileNameMappingFactory.getDefaultFileNameMapping().mapFileName( artifact );
264 }
265
266 /**
267 * The alt-dd element specifies an optional URI to the post-assembly version of the deployment descriptor file for a
268 * particular Java EE module. The URI must specify the full pathname of the deployment descriptor file relative to
269 * the application's root directory.
270 *
271 * @return the alternative deployment descriptor for this module
272 */
273 public String getAltDeploymentDescriptor()
274 {
275 return altDeploymentDescriptor;
276 }
277
278 /**
279 * Specify whether this module should be excluded or not.
280 *
281 * @return true if this module should be skipped, false otherwise
282 */
283 public boolean isExcluded()
284 {
285 return excluded;
286 }
287
288 /**
289 * @return {@link #unpack}
290 */
291 public Boolean shouldUnpack()
292 {
293 return unpack;
294 }
295
296 /**
297 * Writes the alternative deployment descriptor if necessary.
298 *
299 * @param writer the writer to use
300 * @param version the java EE version in use
301 */
302 protected void writeAltDeploymentDescriptor( XMLWriter writer, String version )
303 {
304 if ( getAltDeploymentDescriptor() != null )
305 {
306 writer.startElement( ALT_DD );
307 writer.writeText( getAltDeploymentDescriptor() );
308 writer.endElement();
309 }
310 }
311
312 /**
313 * Starts a new {@link #MODULE_ELEMENT} on the specified writer, possibly including an id attribute.
314 *
315 * @param writer the XML writer.
316 * @param generateId whether an id should be generated
317 */
318 protected void startModuleElement( XMLWriter writer, Boolean generateId )
319 {
320 writer.startElement( MODULE_ELEMENT );
321
322 // If a moduleId is specified, always include it
323 if ( getModuleId() != null )
324 {
325 writer.addAttribute( "id", getModuleId() );
326 }
327 else if ( generateId )
328 {
329 // No module id was specified but one should be generated.
330 Artifact theArtifact = getArtifact();
331 String generatedId =
332 theArtifact.getType().toUpperCase() + "_" + theArtifact.getGroupId() + "."
333 + theArtifact.getArtifactId();
334 if ( null != theArtifact.getClassifier() && theArtifact.getClassifier().trim().length() > 0 )
335 {
336 generatedId += "-" + theArtifact.getClassifier().trim();
337 }
338 writer.addAttribute( "id", generatedId );
339 }
340 }
341
342 /**
343 * {@inheritDoc}
344 */
345 public String toString()
346 {
347 StringBuilder sb = new StringBuilder();
348 sb.append( getType() ).append( ":" ).append( groupId ).append( ":" ).append( artifactId );
349 if ( classifier != null )
350 {
351 sb.append( ":" ).append( classifier );
352 }
353 if ( artifact != null )
354 {
355 sb.append( ":" ).append( artifact.getVersion() );
356 }
357 return sb.toString();
358 }
359
360 /**
361 * Cleans the bundle directory so that it might be used properly.
362 *
363 * @param bundleDir the bundle directory to clean
364 * @return the cleaned bundle directory
365 */
366 static String cleanBundleDir( String bundleDir )
367 {
368 if ( bundleDir == null )
369 {
370 return null;
371 }
372
373 // Using slashes
374 bundleDir = bundleDir.replace( '\\', '/' );
375
376 // Remove '/' prefix if any so that directory is a relative path
377 if ( bundleDir.startsWith( "/" ) )
378 {
379 bundleDir = bundleDir.substring( 1, bundleDir.length() );
380 }
381
382 if ( bundleDir.length() > 0 && !bundleDir.endsWith( "/" ) )
383 {
384 // Adding '/' suffix to specify a directory structure if it is not empty
385 bundleDir = bundleDir + "/";
386 }
387
388 return bundleDir;
389 }
390
391 /**
392 * Specify if the objects are both null or both equal.
393 *
394 * @param first the first object
395 * @param second the second object
396 * @return true if parameters are either both null or equal
397 */
398 static boolean areNullOrEqual( Object first, Object second )
399 {
400 if ( first != null )
401 {
402 return first.equals( second );
403 }
404 else
405 {
406 return second == null;
407 }
408 }
409
410 /**
411 * Sets the URI of the module explicitly for testing purposes.
412 *
413 * @param uri the uri
414 */
415 void setUri( String uri )
416 {
417 this.uri = uri;
418
419 }
420
421 /**
422 * @return always {@code true}
423 */
424 public boolean changeManifestClasspath()
425 {
426 return true;
427 }
428
429 /**
430 * @return always {@code null}
431 */
432 public String getLibDir()
433 {
434 return null;
435 }
436 }