View Javadoc
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 }