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.
122      * Details see
123      * <a href="./examples/customize-file-name-mapping.html">Customizing The File Name Mapping</a>.
124      *
125      * @since 3.0.0
126      */
127     @Parameter( defaultValue = "@{groupId}@-@{artifactId}@-@{version}@@{dashClassifier?}@.@{extension}@",
128                 required = true )
129     private String outputFileNameMapping;
130 
131     /**
132      * Directory that resources are copied to during the build.
133      */
134     @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}", required = true )
135     private File workDirectory;
136 
137     /**
138      * The JBoss specific configuration.
139      * 
140      * @parameter
141      */
142     @Parameter
143     private PlexusConfiguration jboss;
144 
145     /**
146      * The id to use to define the main artifact (e.g. the artifact without a classifier) when there is multiple
147      * candidates.
148      * 
149      * @parameter
150      */
151     @Parameter
152     private String mainArtifactId = "none";
153 
154     private List<EarModule> earModules;
155 
156     private List<EarModule> allEarModules;
157 
158     private List<EarModule> providedEarModules;
159 
160     private JbossConfiguration jbossConfiguration;
161 
162     /** {@inheritDoc} */
163     public void execute()
164         throws MojoExecutionException, MojoFailureException
165     {
166         if ( fileNameMapping != null )
167         {
168             getLog().error( "fileNameMapping has been removed with version 3.0.0. You are still using it." );
169             getLog().error( "Use outputFileNameMapping instead." );
170             throw new MojoExecutionException( "fileNameMapping has been removed with version 3.0.0 "
171                 + "but you are still using it." );
172         }
173 
174         final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion( version );
175         getLog().debug( "Resolving artifact type mappings ..." );
176         ArtifactTypeMappingService typeMappingService;
177         try
178         {
179             typeMappingService = new ArtifactTypeMappingService();
180             typeMappingService.configure( artifactTypeMappings );
181         }
182         catch ( EarPluginException e )
183         {
184             throw new MojoExecutionException( "Failed to initialize artifact type mappings", e );
185         }
186         catch ( PlexusConfigurationException e )
187         {
188             throw new MojoExecutionException( "Invalid artifact type mappings configuration", e );
189         }
190 
191         getLog().debug( "Initializing JBoss configuration if necessary ..." );
192         try
193         {
194             initializeJbossConfiguration();
195         }
196         catch ( EarPluginException e )
197         {
198             throw new MojoExecutionException( "Failed to initialize JBoss configuration", e );
199         }
200 
201         getLog().debug( "Initializing ear execution context" );
202         EarExecutionContext earExecutionContext =
203             new EarExecutionContext( project, mainArtifactId, defaultLibBundleDir, jbossConfiguration,
204                                      outputFileNameMapping, typeMappingService );
205 
206         getLog().debug( "Resolving ear modules ..." );
207         List<EarModule> allModules = new ArrayList<EarModule>();
208         try
209         {
210             if ( modules != null && modules.length > 0 )
211             {
212                 // Let's validate user-defined modules
213                 EarModule module;
214 
215                 for ( EarModule module1 : modules )
216                 {
217                     module = module1;
218                     getLog().debug( "Resolving ear module[" + module + "]" );
219                     module.setEarExecutionContext( earExecutionContext );
220                     module.resolveArtifact( project.getArtifacts() );
221                     allModules.add( module );
222                 }
223             }
224 
225             // Let's add other modules
226             Set<Artifact> artifacts = project.getArtifacts();
227             for ( Artifact artifact : artifacts )
228             {
229                 // If the artifact's type is POM, ignore and continue
230                 // since it's used for transitive deps only.
231                 if ( "pom".equals( artifact.getType() ) )
232                 {
233                     continue;
234                 }
235 
236                 // Artifact is not yet registered and it has not test scope, nor is it optional
237                 ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE_PLUS_RUNTIME );
238                 if ( !isArtifactRegistered( artifact, allModules ) && !artifact.isOptional()
239                     && filter.include( artifact ) )
240                 {
241                     EarModule module = EarModuleFactory.newEarModule( artifact, javaEEVersion, defaultLibBundleDir,
242                                                                       includeLibInApplicationXml, typeMappingService );
243                     module.setEarExecutionContext( earExecutionContext );
244                     allModules.add( module );
245                 }
246             }
247         }
248         catch ( EarPluginException e )
249         {
250             throw new MojoExecutionException( "Failed to initialize ear modules", e );
251         }
252 
253         // Now we have everything let's built modules which have not been excluded
254         ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
255         allEarModules = new ArrayList<>();
256         providedEarModules = new ArrayList<>();
257         earModules = new ArrayList<>();
258         for ( EarModule earModule : allModules )
259         {
260             if ( earModule.isExcluded() )
261             {
262                 getLog().debug( "Skipping ear module[" + earModule + "]" );
263             }
264             else
265             {
266                 allEarModules.add( earModule );
267                 if ( filter.include( earModule.getArtifact() ) )
268                 {
269                     earModules.add( earModule );
270                 }
271                 else
272                 {
273                     providedEarModules.add( earModule );
274                 }
275             }
276         }
277 
278     }
279 
280     /**
281      * @return The list of {@link #earModules}. This corresponds to modules needed at runtime.
282      */
283     protected List<EarModule> getModules()
284     {
285         if ( earModules == null )
286         {
287             throw new IllegalStateException( "Ear modules have not been initialized" );
288         }
289         return earModules;
290     }
291 
292     /**
293      * @return The list of {@link #allEarModules}. This corresponds to all modules (provided + compile + runtime).
294      */
295     protected List<EarModule> getAllEarModules()
296     {
297         if ( allEarModules == null )
298         {
299             throw new IllegalStateException( "EAR modules have not been initialized" );
300         }
301         return allEarModules;
302     }
303 
304     /**
305      * @return the list of {@link #providedEarModules}. This corresponds to provided modules.
306      */
307     protected List<EarModule> getProvidedEarModules()
308     {
309         if ( providedEarModules == null )
310         {
311             throw new IllegalStateException( "Jar modules have not been initialized" );
312         }
313         return providedEarModules;
314     }
315 
316     /**
317      * @return {@link MavenProject}
318      */
319     protected MavenProject getProject()
320     {
321         return project;
322     }
323 
324     /**
325      * @return {@link #workDirectory}
326      */
327     protected File getWorkDirectory()
328     {
329         return workDirectory;
330     }
331 
332     /**
333      * @return {@link #jbossConfiguration}
334      */
335     protected JbossConfiguration getJbossConfiguration()
336     {
337         return jbossConfiguration;
338     }
339 
340     /**
341      * @return {@link #outputFileNameMapping}
342      */
343     public String getOutputFileNameMapping()
344     {
345         return outputFileNameMapping;
346     }
347 
348     private static boolean isArtifactRegistered( Artifact a, List<EarModule> currentList )
349     {
350         for ( EarModule em : currentList )
351         {
352             if ( em.getArtifact().equals( a ) )
353             {
354                 return true;
355             }
356         }
357         return false;
358     }
359 
360     /**
361      * Initializes the JBoss configuration.
362      * 
363      * @throws EarPluginException if the configuration is invalid
364      */
365     private void initializeJbossConfiguration()
366         throws EarPluginException
367     {
368         if ( jboss == null )
369         {
370             jbossConfiguration = null;
371         }
372         else
373         {
374             String childVersion = jboss.getChild( JbossConfiguration.VERSION ).getValue();
375             if ( childVersion == null )
376             {
377                 getLog().info( "JBoss version not set, using JBoss 4 by default" );
378                 childVersion = JbossConfiguration.VERSION_4;
379             }
380             final String securityDomain = jboss.getChild( JbossConfiguration.SECURITY_DOMAIN ).getValue();
381             final String unauthenticatedPrincipal =
382                 jboss.getChild( JbossConfiguration.UNAUHTHENTICTED_PRINCIPAL ).getValue();
383 
384             final PlexusConfiguration loaderRepositoryEl = jboss.getChild( JbossConfiguration.LOADER_REPOSITORY );
385             final String loaderRepository = loaderRepositoryEl.getValue();
386             final String loaderRepositoryClass =
387                 loaderRepositoryEl.getAttribute( JbossConfiguration.LOADER_REPOSITORY_CLASS_ATTRIBUTE );
388             final PlexusConfiguration loaderRepositoryConfigEl =
389                 jboss.getChild( JbossConfiguration.LOADER_REPOSITORY_CONFIG );
390             final String loaderRepositoryConfig = loaderRepositoryConfigEl.getValue();
391             final String configParserClass =
392                 loaderRepositoryConfigEl.getAttribute( JbossConfiguration.CONFIG_PARSER_CLASS_ATTRIBUTE );
393 
394             final String jmxName = jboss.getChild( JbossConfiguration.JMX_NAME ).getValue();
395             final String moduleOrder = jboss.getChild( JbossConfiguration.MODULE_ORDER ).getValue();
396 
397             final List<String> dataSources = new ArrayList<String>();
398             final PlexusConfiguration dataSourcesEl = jboss.getChild( JbossConfiguration.DATASOURCES );
399             if ( dataSourcesEl != null )
400             {
401 
402                 final PlexusConfiguration[] dataSourcesConfig =
403                     dataSourcesEl.getChildren( JbossConfiguration.DATASOURCE );
404                 for ( PlexusConfiguration dataSourceConfig : dataSourcesConfig )
405                 {
406                     dataSources.add( dataSourceConfig.getValue() );
407 
408                 }
409             }
410             final String libraryDirectory = jboss.getChild( JbossConfiguration.LIBRARY_DIRECTORY ).getValue();
411             jbossConfiguration =
412                 new JbossConfiguration( childVersion, securityDomain, unauthenticatedPrincipal, jmxName,
413                                         loaderRepository, moduleOrder, dataSources, libraryDirectory,
414                                         loaderRepositoryConfig, loaderRepositoryClass, configParserClass );
415         }
416     }
417 }