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.io.File;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Set;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
29  import org.apache.maven.plugin.AbstractMojo;
30  import org.apache.maven.plugin.MojoExecutionException;
31  import org.apache.maven.plugin.MojoFailureException;
32  import org.apache.maven.plugins.annotations.Parameter;
33  import org.apache.maven.plugins.ear.util.ArtifactTypeMappingService;
34  import org.apache.maven.plugins.ear.util.JavaEEVersion;
35  import org.apache.maven.project.MavenProject;
36  import org.codehaus.plexus.configuration.PlexusConfiguration;
37  import org.codehaus.plexus.configuration.PlexusConfigurationException;
38  
39  /**
40   * A base class for EAR-processing related tasks.
41   * 
42   * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
43   */
44  public abstract class AbstractEarMojo
45      extends AbstractMojo
46  {
47      /**
48       * The application XML URI {@code META-INF/application.xml}
49       */
50      public static final String APPLICATION_XML_URI = "META-INF/application.xml";
51  
52      /**
53       * The {@code META-INF} folder.
54       */
55      public static final String META_INF = "META-INF";
56  
57      /**
58       * UTF-8 encoding constant.
59       */
60      public static final String UTF_8 = "UTF-8";
61  
62      /**
63       * The version of the application.xml to generate. Valid values are 1.3, 1.4, 5, 6, 7 and 8.
64       */
65      @Parameter( defaultValue = "7" )
66      protected String version;
67  
68      /**
69       * Character encoding for the auto-generated deployment file(s).
70       */
71      @Parameter( defaultValue = "UTF-8" )
72      protected String encoding;
73  
74      /**
75       * Directory where the deployment descriptor file(s) will be auto-generated.
76       */
77      @Parameter( defaultValue = "${project.build.directory}" )
78      protected String generatedDescriptorLocation;
79  
80      /**
81       * The maven project.
82       */
83      @Parameter( defaultValue = "${project}", readonly = true, required = true )
84      protected MavenProject project;
85  
86      /**
87       * The ear modules configuration.
88       */
89      @Parameter
90      private EarModule[] modules;
91  
92      /**
93       * The artifact type mappings.
94       */
95      @Parameter
96      protected PlexusConfiguration artifactTypeMappings;
97  
98      /**
99       * The default bundle dir for libraries.
100      */
101     @Parameter
102     protected String defaultLibBundleDir;
103 
104     /**
105      * Should libraries be added in application.xml
106      */
107     @Parameter( defaultValue = "false" )
108     private Boolean includeLibInApplicationXml = Boolean.FALSE;
109 
110     /**
111      * Only here to identify migration issues. The usage of this parameter will fail the build. If you need file name
112      * mapping please use {@link #outputFileNameMapping} instead.
113      * 
114      * @deprecated
115      */
116     @Parameter
117     private String fileNameMapping;
118 
119     /**
120      * The file name mapping to use for all dependencies included in the EAR file. The mapping between artifacts and the
121      * file names which is used within the EAR file. Details see
122      * <a href="http://maven.apache.org/shared/maven-mapping/index.html">Maven Mapping Reference</a>.
123      * 
124      * @since 3.0.0
125      */
126     // CHECKSTYLE_OFF: LineLength
127     @Parameter( defaultValue = "@{groupId}@-@{artifactId}@-@{version}@@{dashClassifier?}@.@{extension}@", required = true )
128     private String outputFileNameMapping;
129     // CHECKSTYLE_ON: LineLength
130 
131     /**
132      * When using a {@link #outputFileNameMapping} with versions, either use the {@code baseVersion} or the
133      * {@code version}. When the artifact is a SNAPSHOT, {@code version} will always return a value with a
134      * {@code -SNAPSHOT} postfix instead of the possible timestamped value.
135      */
136     @Parameter
137     private Boolean useBaseVersion;
138 
139     /**
140      * Directory that resources are copied to during the build.
141      */
142     @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}", required = true )
143     private File workDirectory;
144 
145     /**
146      * The JBoss specific configuration.
147      * 
148      * @parameter
149      */
150     @Parameter
151     private PlexusConfiguration jboss;
152 
153     /**
154      * The id to use to define the main artifact (e.g. the artifact without a classifier) when there is multiple
155      * candidates.
156      * 
157      * @parameter
158      */
159     @Parameter
160     private String mainArtifactId = "none";
161 
162     /**
163      * temp folder location.
164      */
165     @Parameter( defaultValue = "${project.build.directory}", required = true )
166     private File tempFolder;
167 
168     private List<EarModule> earModules;
169 
170     private List<JarModule> allJarModules;
171 
172     private JbossConfiguration jbossConfiguration;
173 
174     /** {@inheritDoc} */
175     public void execute()
176         throws MojoExecutionException, MojoFailureException
177     {
178         if ( fileNameMapping != null )
179         {
180             getLog().error( "fileNameMapping has been removed with version 3.0.0. You are still using it." );
181             getLog().error( "Use outputFileNameMapping instead." );
182             throw new MojoExecutionException( "fileNameMapping has ben removed with version 3.0.0 "
183                 + "but you are still using it." );
184         }
185 
186         final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion( version );
187         getLog().debug( "Resolving artifact type mappings ..." );
188         ArtifactTypeMappingService typeMappingService;
189         try
190         {
191             typeMappingService = new ArtifactTypeMappingService();
192             typeMappingService.configure( artifactTypeMappings );
193         }
194         catch ( EarPluginException e )
195         {
196             throw new MojoExecutionException( "Failed to initialize artifact type mappings", e );
197         }
198         catch ( PlexusConfigurationException e )
199         {
200             throw new MojoExecutionException( "Invalid artifact type mappings configuration", e );
201         }
202 
203         getLog().debug( "Initializing JBoss configuration if necessary ..." );
204         try
205         {
206             initializeJbossConfiguration();
207         }
208         catch ( EarPluginException e )
209         {
210             throw new MojoExecutionException( "Failed to initialize JBoss configuration", e );
211         }
212 
213         getLog().debug( "Initializing ear execution context" );
214         EarExecutionContext earExecutionContext =
215             new EarExecutionContext( project, mainArtifactId, defaultLibBundleDir, jbossConfiguration,
216                                      outputFileNameMapping, typeMappingService );
217 
218         if ( useBaseVersion != null )
219         {
220             getLog().warn( "Using useBaseVersion not yet fixed." );
221             // earExecutionContext.getOutputFileNameMapping().setUseBaseVersion( useBaseVersion );
222         }
223 
224         getLog().debug( "Resolving ear modules ..." );
225         List<EarModule> allModules = new ArrayList<EarModule>();
226         try
227         {
228             if ( modules != null && modules.length > 0 )
229             {
230                 // Let's validate user-defined modules
231                 EarModule module;
232 
233                 for ( EarModule module1 : modules )
234                 {
235                     module = module1;
236                     getLog().debug( "Resolving ear module[" + module + "]" );
237                     module.setEarExecutionContext( earExecutionContext );
238                     module.resolveArtifact( project.getArtifacts() );
239                     allModules.add( module );
240                 }
241             }
242 
243             // Let's add other modules
244             Set<Artifact> artifacts = project.getArtifacts();
245             for ( Artifact artifact : artifacts )
246             {
247                 // If the artifact's type is POM, ignore and continue
248                 // since it's used for transitive deps only.
249                 if ( "pom".equals( artifact.getType() ) )
250                 {
251                     continue;
252                 }
253 
254                 // Artifact is not yet registered and it has not test scope, nor is it optional
255                 ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE_PLUS_RUNTIME );
256                 if ( !isArtifactRegistered( artifact, allModules ) && !artifact.isOptional()
257                     && filter.include( artifact ) )
258                 {
259                     EarModule module = EarModuleFactory.newEarModule( artifact, javaEEVersion, defaultLibBundleDir,
260                                                                       includeLibInApplicationXml, typeMappingService );
261                     module.setEarExecutionContext( earExecutionContext );
262                     allModules.add( module );
263                 }
264             }
265         }
266         catch ( EarPluginException e )
267         {
268             throw new MojoExecutionException( "Failed to initialize ear modules", e );
269         }
270 
271         // Now we have everything let's built modules which have not been excluded
272         ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
273         allJarModules = new ArrayList<JarModule>();
274         earModules = new ArrayList<EarModule>();
275         for ( EarModule earModule : allModules )
276         {
277             if ( earModule.isExcluded() )
278             {
279                 getLog().debug( "Skipping ear module[" + earModule + "]" );
280             }
281             else
282             {
283                 if ( earModule instanceof JarModule )
284                 {
285                     allJarModules.add( (JarModule) earModule );
286                 }
287                 if ( filter.include( earModule.getArtifact() ) )
288                 {
289                     earModules.add( earModule );
290                 }
291             }
292         }
293 
294     }
295 
296     /**
297      * @return The list of {@link #earModules}. This corresponds to modules needed at runtime.
298      */
299     protected List<EarModule> getModules()
300     {
301         if ( earModules == null )
302         {
303             throw new IllegalStateException( "Ear modules have not been initialized" );
304         }
305         return earModules;
306     }
307 
308     /**
309      * @return The list of {@link #allJarModules}. This corresponds to all JAR modules (compile + runtime).
310      */
311     protected List<JarModule> getAllJarModules()
312     {
313         if ( allJarModules == null )
314         {
315             throw new IllegalStateException( "Jar modules have not been initialized" );
316         }
317         return allJarModules;
318     }
319 
320     /**
321      * @return {@link MavenProject}
322      */
323     protected MavenProject getProject()
324     {
325         return project;
326     }
327 
328     /**
329      * @return {@link #workDirectory}
330      */
331     protected File getWorkDirectory()
332     {
333         return workDirectory;
334     }
335 
336     /**
337      * @return {@link #jbossConfiguration}
338      */
339     protected JbossConfiguration getJbossConfiguration()
340     {
341         return jbossConfiguration;
342     }
343 
344     /**
345      * @return {@link #tempFolder}
346      */
347     public File getTempFolder()
348     {
349         return tempFolder;
350     }
351 
352     /**
353      * @return {@link #outputFileNameMapping}
354      */
355     public String getOutputFileNameMapping()
356     {
357         return outputFileNameMapping;
358     }
359 
360     private static boolean isArtifactRegistered( Artifact a, List<EarModule> currentList )
361     {
362         for ( EarModule em : currentList )
363         {
364             if ( em.getArtifact().equals( a ) )
365             {
366                 return true;
367             }
368         }
369         return false;
370     }
371 
372     /**
373      * Initializes the JBoss configuration.
374      * 
375      * @throws EarPluginException if the configuration is invalid
376      */
377     private void initializeJbossConfiguration()
378         throws EarPluginException
379     {
380         if ( jboss == null )
381         {
382             jbossConfiguration = null;
383         }
384         else
385         {
386             String childVersion = jboss.getChild( JbossConfiguration.VERSION ).getValue();
387             if ( childVersion == null )
388             {
389                 getLog().info( "JBoss version not set, using JBoss 4 by default" );
390                 childVersion = JbossConfiguration.VERSION_4;
391             }
392             final String securityDomain = jboss.getChild( JbossConfiguration.SECURITY_DOMAIN ).getValue();
393             final String unauthenticatedPrincipal =
394                 jboss.getChild( JbossConfiguration.UNAUHTHENTICTED_PRINCIPAL ).getValue();
395 
396             final PlexusConfiguration loaderRepositoryEl = jboss.getChild( JbossConfiguration.LOADER_REPOSITORY );
397             final String loaderRepository = loaderRepositoryEl.getValue();
398             final String loaderRepositoryClass =
399                 loaderRepositoryEl.getAttribute( JbossConfiguration.LOADER_REPOSITORY_CLASS_ATTRIBUTE );
400             final PlexusConfiguration loaderRepositoryConfigEl =
401                 jboss.getChild( JbossConfiguration.LOADER_REPOSITORY_CONFIG );
402             final String loaderRepositoryConfig = loaderRepositoryConfigEl.getValue();
403             final String configParserClass =
404                 loaderRepositoryConfigEl.getAttribute( JbossConfiguration.CONFIG_PARSER_CLASS_ATTRIBUTE );
405 
406             final String jmxName = jboss.getChild( JbossConfiguration.JMX_NAME ).getValue();
407             final String moduleOrder = jboss.getChild( JbossConfiguration.MODULE_ORDER ).getValue();
408 
409             final List<String> dataSources = new ArrayList<String>();
410             final PlexusConfiguration dataSourcesEl = jboss.getChild( JbossConfiguration.DATASOURCES );
411             if ( dataSourcesEl != null )
412             {
413 
414                 final PlexusConfiguration[] dataSourcesConfig =
415                     dataSourcesEl.getChildren( JbossConfiguration.DATASOURCE );
416                 for ( PlexusConfiguration dataSourceConfig : dataSourcesConfig )
417                 {
418                     dataSources.add( dataSourceConfig.getValue() );
419 
420                 }
421             }
422             final String libraryDirectory = jboss.getChild( JbossConfiguration.LIBRARY_DIRECTORY ).getValue();
423             jbossConfiguration =
424                 new JbossConfiguration( childVersion, securityDomain, unauthenticatedPrincipal, jmxName,
425                                         loaderRepository, moduleOrder, dataSources, libraryDirectory,
426                                         loaderRepositoryConfig, loaderRepositoryClass, configParserClass );
427         }
428     }
429 }