View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.ear;
20  
21  import java.io.File;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.apache.maven.artifact.Artifact;
27  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
28  import org.apache.maven.plugin.AbstractMojo;
29  import org.apache.maven.plugin.MojoExecutionException;
30  import org.apache.maven.plugin.MojoFailureException;
31  import org.apache.maven.plugins.annotations.Parameter;
32  import org.apache.maven.plugins.ear.util.ArtifactTypeMappingService;
33  import org.apache.maven.plugins.ear.util.JavaEEVersion;
34  import org.apache.maven.project.MavenProject;
35  import org.codehaus.plexus.configuration.PlexusConfiguration;
36  import org.codehaus.plexus.configuration.PlexusConfigurationException;
37  
38  /**
39   * A base class for EAR-processing related tasks.
40   *
41   * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
42   */
43  public abstract class AbstractEarMojo extends AbstractMojo {
44      /**
45       * The application XML URI {@code META-INF/application.xml}
46       */
47      public static final String APPLICATION_XML_URI = "META-INF/application.xml";
48  
49      /**
50       * The {@code META-INF} folder.
51       */
52      public static final String META_INF = "META-INF";
53  
54      /**
55       * UTF-8 encoding constant.
56       */
57      public static final String UTF_8 = "UTF-8";
58  
59      /**
60       * The schema version of generated <code>application.xml</code> descriptor.
61       * <p>
62       * Valid values are 1.3, 1.4, 5, 6, 7, 8, 9, 10 and 11.
63       * <p>
64       * See: <a href="https://jakarta.ee/xml/ns/jakartaee/">Jakarta EE XML Schemas</a>
65       */
66      @Parameter(defaultValue = "7")
67      protected String version;
68  
69      /**
70       * Character encoding for the auto-generated deployment file(s).
71       */
72      @Parameter(defaultValue = "UTF-8")
73      protected String encoding;
74  
75      /**
76       * Directory where the deployment descriptor file(s) will be auto-generated.
77       */
78      @Parameter(defaultValue = "${project.build.directory}")
79      protected String generatedDescriptorLocation;
80  
81      /**
82       * The maven project.
83       */
84      @Parameter(defaultValue = "${project}", readonly = true, required = true)
85      protected MavenProject project;
86  
87      /**
88       * The ear modules configuration.
89       */
90      @Parameter
91      private EarModule[] modules;
92  
93      /**
94       * The artifact type mappings.
95       */
96      @Parameter
97      protected PlexusConfiguration artifactTypeMappings;
98  
99      /**
100      * The default bundle dir for libraries.
101      */
102     @Parameter
103     protected String defaultLibBundleDir;
104 
105     /**
106      * Should libraries be added in application.xml
107      */
108     @Parameter(defaultValue = "false")
109     private Boolean includeLibInApplicationXml = Boolean.FALSE;
110 
111     /**
112      * Only here to identify migration issues. The usage of this parameter will fail the build.
113      *
114      * @deprecated use {@link #outputFileNameMapping}
115      */
116     @Deprecated
117     @Parameter
118     private String fileNameMapping;
119 
120     /**
121      * The file name mapping to use for all dependencies included in the EAR file. The mapping between artifacts and the
122      * file names which is used within the EAR file.
123      * See
124      * <a href="./examples/customize-file-name-mapping.html">Customizing The File Name Mapping</a>.
125      *
126      * @since 3.0.0
127      */
128     @Parameter(
129             defaultValue = "@{groupId}@-@{artifactId}@-@{version}@@{dashClassifier?}@.@{extension}@",
130             required = true)
131     private String outputFileNameMapping;
132 
133     /**
134      * Directory that resources are copied to during the build.
135      */
136     @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}", required = true)
137     private File workDirectory;
138 
139     /**
140      * The JBoss specific configuration.
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 are multiple
147      * candidates.
148      */
149     @Parameter
150     private String mainArtifactId = "none";
151 
152     private List<EarModule> earModules;
153 
154     private List<EarModule> allEarModules;
155 
156     private List<EarModule> providedEarModules;
157 
158     private JbossConfiguration jbossConfiguration;
159 
160     /** {@inheritDoc} */
161     @Override
162     public void execute() throws MojoExecutionException, MojoFailureException {
163         if (fileNameMapping != null) {
164             getLog().error("fileNameMapping has been removed with version 3.0.0. You are still using it.");
165             getLog().error("Use outputFileNameMapping instead.");
166             throw new MojoExecutionException(
167                     "fileNameMapping has been removed with version 3.0.0 " + "but you are still using it.");
168         }
169 
170         final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion(version);
171         getLog().debug("Resolving artifact type mappings ...");
172         ArtifactTypeMappingService typeMappingService;
173         try {
174             typeMappingService = new ArtifactTypeMappingService();
175             typeMappingService.configure(artifactTypeMappings);
176         } catch (EarPluginException e) {
177             throw new MojoExecutionException("Failed to initialize artifact type mappings", e);
178         } catch (PlexusConfigurationException e) {
179             throw new MojoExecutionException("Invalid artifact type mappings configuration", e);
180         }
181 
182         getLog().debug("Initializing JBoss configuration if necessary ...");
183         try {
184             initializeJbossConfiguration();
185         } catch (EarPluginException e) {
186             throw new MojoExecutionException("Failed to initialize JBoss configuration", e);
187         }
188 
189         getLog().debug("Initializing ear execution context");
190         EarExecutionContext earExecutionContext = new EarExecutionContext(
191                 project,
192                 mainArtifactId,
193                 defaultLibBundleDir,
194                 jbossConfiguration,
195                 outputFileNameMapping,
196                 typeMappingService);
197 
198         getLog().debug("Resolving ear modules ...");
199         List<EarModule> allModules = new ArrayList<>();
200         try {
201             if (modules != null) {
202                 // Let's validate user-defined modules
203                 for (EarModule module : modules) {
204                     getLog().debug("Resolving ear module[" + module + "]");
205                     module.setEarExecutionContext(earExecutionContext);
206                     module.resolveArtifact(project.getArtifacts());
207                     allModules.add(module);
208                 }
209             }
210 
211             // Let's add other modules
212             Set<Artifact> artifacts = project.getArtifacts();
213             for (Artifact artifact : artifacts) {
214                 // If the artifact's type is POM, ignore and continue
215                 // since it's used for transitive deps only.
216                 if ("pom".equals(artifact.getType())) {
217                     continue;
218                 }
219 
220                 // Artifact is not yet registered and it has not test scope, nor is it optional
221                 ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE_PLUS_RUNTIME);
222                 if (!isArtifactRegistered(artifact, allModules) && !artifact.isOptional() && filter.include(artifact)) {
223                     EarModule module = EarModuleFactory.newEarModule(
224                             artifact,
225                             javaEEVersion,
226                             defaultLibBundleDir,
227                             includeLibInApplicationXml,
228                             typeMappingService);
229                     module.setEarExecutionContext(earExecutionContext);
230                     allModules.add(module);
231                 }
232             }
233         } catch (EarPluginException e) {
234             throw new MojoExecutionException("Failed to initialize ear modules", e);
235         }
236 
237         // Now we have everything. Let's build modules which have not been excluded
238         ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
239         allEarModules = new ArrayList<>();
240         providedEarModules = new ArrayList<>();
241         earModules = new ArrayList<>();
242         for (EarModule earModule : allModules) {
243             if (earModule.isExcluded()) {
244                 getLog().debug("Skipping ear module[" + earModule + "]");
245             } else {
246                 allEarModules.add(earModule);
247                 if (filter.include(earModule.getArtifact())) {
248                     earModules.add(earModule);
249                 } else {
250                     providedEarModules.add(earModule);
251                 }
252             }
253         }
254     }
255 
256     /**
257      * @return the list of {@link #earModules}. This corresponds to modules needed at runtime.
258      */
259     protected List<EarModule> getModules() {
260         if (earModules == null) {
261             throw new IllegalStateException("Ear modules have not been initialized");
262         }
263         return earModules;
264     }
265 
266     /**
267      * @return the list of {@link #allEarModules}. This corresponds to all modules (provided + compile + runtime).
268      */
269     protected List<EarModule> getAllEarModules() {
270         if (allEarModules == null) {
271             throw new IllegalStateException("EAR modules have not been initialized");
272         }
273         return allEarModules;
274     }
275 
276     /**
277      * @return the list of {@link #providedEarModules}. This corresponds to provided modules.
278      */
279     protected List<EarModule> getProvidedEarModules() {
280         if (providedEarModules == null) {
281             throw new IllegalStateException("Jar modules have not been initialized");
282         }
283         return providedEarModules;
284     }
285 
286     /**
287      * @return {@link MavenProject}
288      */
289     protected MavenProject getProject() {
290         return project;
291     }
292 
293     /**
294      * @return {@link #workDirectory}
295      */
296     protected File getWorkDirectory() {
297         return workDirectory;
298     }
299 
300     /**
301      * @return {@link #jbossConfiguration}
302      */
303     protected JbossConfiguration getJbossConfiguration() {
304         return jbossConfiguration;
305     }
306 
307     /**
308      * @return {@link #outputFileNameMapping}
309      */
310     public String getOutputFileNameMapping() {
311         return outputFileNameMapping;
312     }
313 
314     private static boolean isArtifactRegistered(Artifact a, List<EarModule> currentList) {
315         for (EarModule em : currentList) {
316             if (em.getArtifact().equals(a)) {
317                 return true;
318             }
319         }
320         return false;
321     }
322 
323     /**
324      * Initializes the JBoss configuration.
325      *
326      * @throws EarPluginException if the configuration is invalid
327      */
328     private void initializeJbossConfiguration() throws EarPluginException {
329         if (jboss == null) {
330             jbossConfiguration = null;
331         } else {
332             String childVersion = jboss.getChild(JbossConfiguration.VERSION).getValue();
333             if (childVersion == null) {
334                 getLog().info("JBoss version not set, using JBoss 4 by default");
335                 childVersion = JbossConfiguration.VERSION_4;
336             }
337             final String securityDomain =
338                     jboss.getChild(JbossConfiguration.SECURITY_DOMAIN).getValue();
339             final String unauthenticatedPrincipal =
340                     jboss.getChild(JbossConfiguration.UNAUHTHENTICTED_PRINCIPAL).getValue();
341 
342             final PlexusConfiguration loaderRepositoryEl = jboss.getChild(JbossConfiguration.LOADER_REPOSITORY);
343             final String loaderRepository = loaderRepositoryEl.getValue();
344             final String loaderRepositoryClass =
345                     loaderRepositoryEl.getAttribute(JbossConfiguration.LOADER_REPOSITORY_CLASS_ATTRIBUTE);
346             final PlexusConfiguration loaderRepositoryConfigEl =
347                     jboss.getChild(JbossConfiguration.LOADER_REPOSITORY_CONFIG);
348             final String loaderRepositoryConfig = loaderRepositoryConfigEl.getValue();
349             final String configParserClass =
350                     loaderRepositoryConfigEl.getAttribute(JbossConfiguration.CONFIG_PARSER_CLASS_ATTRIBUTE);
351 
352             final String jmxName = jboss.getChild(JbossConfiguration.JMX_NAME).getValue();
353             final String moduleOrder =
354                     jboss.getChild(JbossConfiguration.MODULE_ORDER).getValue();
355 
356             final List<String> dataSources = new ArrayList<>();
357             final PlexusConfiguration dataSourcesEl = jboss.getChild(JbossConfiguration.DATASOURCES);
358             if (dataSourcesEl != null) {
359 
360                 final PlexusConfiguration[] dataSourcesConfig =
361                         dataSourcesEl.getChildren(JbossConfiguration.DATASOURCE);
362                 for (PlexusConfiguration dataSourceConfig : dataSourcesConfig) {
363                     dataSources.add(dataSourceConfig.getValue());
364                 }
365             }
366             final String libraryDirectory =
367                     jboss.getChild(JbossConfiguration.LIBRARY_DIRECTORY).getValue();
368             jbossConfiguration = new JbossConfiguration(
369                     childVersion,
370                     securityDomain,
371                     unauthenticatedPrincipal,
372                     jmxName,
373                     loaderRepository,
374                     moduleOrder,
375                     dataSources,
376                     libraryDirectory,
377                     loaderRepositoryConfig,
378                     loaderRepositoryClass,
379                     configParserClass);
380         }
381     }
382 }