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