Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarMojo.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarMojo.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarMojo.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarMojo.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,891 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.zip.ZipException; + +import org.apache.maven.archiver.MavenArchiveConfiguration; +import org.apache.maven.archiver.MavenArchiver; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.plugins.ear.util.EarMavenArchiver; +import org.apache.maven.plugins.ear.util.JavaEEVersion; +import org.apache.maven.plugins.ear.util.ModuleIdentifierValidator; +import org.apache.maven.project.MavenProjectHelper; +import org.apache.maven.shared.filtering.MavenFileFilter; +import org.apache.maven.shared.filtering.MavenFilteringException; +import org.apache.maven.shared.filtering.MavenResourcesExecution; +import org.apache.maven.shared.filtering.MavenResourcesFiltering; +import org.apache.maven.shared.utils.io.FileUtils; +import org.codehaus.plexus.archiver.Archiver; +import org.codehaus.plexus.archiver.ArchiverException; +import org.codehaus.plexus.archiver.UnArchiver; +import org.codehaus.plexus.archiver.jar.JarArchiver; +import org.codehaus.plexus.archiver.jar.Manifest; +import org.codehaus.plexus.archiver.jar.Manifest.Attribute; +import org.codehaus.plexus.archiver.jar.ManifestException; +import org.codehaus.plexus.archiver.manager.ArchiverManager; +import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; +import org.codehaus.plexus.archiver.zip.ZipArchiver; +import org.codehaus.plexus.archiver.zip.ZipUnArchiver; +import org.codehaus.plexus.util.DirectoryScanner; +import org.codehaus.plexus.util.StringUtils; + +/** + * Builds J2EE Enterprise Archive (EAR) files. + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: EarMojo.java 1755539 2016-08-08 20:34:46Z rfscholte $ + */ +// CHECKSTYLE_OFF: LineLength +@Mojo( name = "ear", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST ) +// CHECKSTYLE_ON: LineLength +public class EarMojo + extends AbstractEarMojo +{ + /** + * Single directory for extra files to include in the EAR. + */ + @Parameter( defaultValue = "${basedir}/src/main/application", required = true ) + private File earSourceDirectory; + + /** + * The comma separated list of tokens to include in the EAR. + */ + @Parameter( alias = "includes", defaultValue = "**" ) + private String earSourceIncludes; + + /** + * The comma separated list of tokens to exclude from the EAR. + */ + @Parameter( alias = "excludes" ) + private String earSourceExcludes; + + /** + * Specify that the EAR sources should be filtered. + * + * @since 2.3.2 + */ + @Parameter( defaultValue = "false" ) + private boolean filtering; + + /** + * Filters (property files) to include during the interpolation of the pom.xml. + * + * @since 2.3.2 + */ + @Parameter + private List<String> filters; + + /** + * A list of file extensions that should not be filtered if filtering is enabled. + * + * @since 2.3.2 + */ + @Parameter + private List<String> nonFilteredFileExtensions; + + /** + * To escape interpolated value with Windows path c:\foo\bar will be replaced with c:\\foo\\bar. + * + * @since 2.3.2 + */ + @Parameter( property = "maven.ear.escapedBackslashesInFilePath", defaultValue = "false" ) + private boolean escapedBackslashesInFilePath; + + /** + * Expression preceded with this String won't be interpolated \${foo} will be replaced with ${foo}. + * + * @since 2.3.2 + */ + @Parameter( property = "maven.ear.escapeString" ) + protected String escapeString; + + /** + * In case of using the {@link #skinnyWars} and {@link #defaultLibBundleDir} usually the + * classpath will be modified. + * By settings this option {@code true} you can change this and keep the classpath untouched. + * This option has been introduced to keep the backward compatibility with earlier versions + * of the plugin. + * + * @since 2.10 + */ + @Parameter( defaultValue = "false" ) + private boolean skipClassPathModification; + + /** + * The location of the manifest file to be used within the EAR file. If no value if specified, the default location + * in the workDirectory is taken. If the file does not exist, a manifest will be generated automatically. + */ + @Parameter + private File manifestFile; + + /** + * The location of a custom application.xml file to be used within the EAR file. + */ + @Parameter + private String applicationXml; + + /** + * The directory for the generated EAR. + */ + @Parameter( defaultValue = "${project.build.directory}", required = true ) + private String outputDirectory; + + /** + * The name of the EAR file to generate. + */ + @Parameter( alias = "earName", defaultValue = "${project.build.finalName}", required = true ) + private String finalName; + + /** + * The comma separated list of artifact's type(s) to unpack by default. + */ + @Parameter + private String unpackTypes; + + /** + * Classifier to add to the artifact generated. If given, the artifact will be an attachment instead. + */ + @Parameter + private String classifier; + + /** + * A comma separated list of tokens to exclude when packaging the EAR. By default nothing is excluded. Note that you + * can use the Java Regular Expressions engine to include and exclude specific pattern using the expression + * %regex[]. Hint: read the about (?!Pattern). + * + * @since 2.7 + */ + @Parameter + private String packagingExcludes; + + /** + * A comma separated list of tokens to include when packaging the EAR. By default everything is included. Note that + * you can use the Java Regular Expressions engine to include and exclude specific pattern using the expression + * %regex[]. + * + * @since 2.7 + */ + @Parameter + private String packagingIncludes; + + /** + * Whether to create skinny WARs or not. A skinny WAR is a WAR that does not have all of its dependencies in + * WEB-INF/lib. Instead those dependencies are shared between the WARs through the EAR. + * + * @since 2.7 + */ + @Parameter( property = "maven.ear.skinnyWars", defaultValue = "false" ) + private boolean skinnyWars; + + /** + * The Jar archiver. + */ + @Component( role = Archiver.class, hint = "jar" ) + private JarArchiver jarArchiver; + + /** + * The Zip archiver. + */ + @Component( role = Archiver.class, hint = "zip" ) + private ZipArchiver zipArchiver; + + /** + * The Zip Un archiver. + */ + @Component( role = UnArchiver.class, hint = "zip" ) + private ZipUnArchiver zipUnArchiver; + + /** + * The archive configuration to use. See <a href="http://maven.apache.org/shared/maven-archiver/index.html">Maven + * Archiver Reference</a>. + */ + @Parameter + private MavenArchiveConfiguration archive = new MavenArchiveConfiguration(); + + /** + */ + @Component + private MavenProjectHelper projectHelper; + + /** + * The archive manager. + */ + @Component + private ArchiverManager archiverManager; + + /** + */ + @Component( role = MavenFileFilter.class, hint = "default" ) + private MavenFileFilter mavenFileFilter; + + /** + */ + @Component( role = MavenResourcesFiltering.class, hint = "default" ) + private MavenResourcesFiltering mavenResourcesFiltering; + + /** + * @since 2.3.2 + */ + @Parameter( defaultValue = "${session}", readonly = true, required = true ) + private MavenSession session; + + private List<FileUtils.FilterWrapper> filterWrappers; + + /** + * @since 2.9 + */ + @Parameter( property = "maven.ear.useJvmChmod", defaultValue = "true" ) + private boolean useJvmChmod = true; + + /** + * The list of artifacts is checked and if you set this to {@code true} the build will fail if duplicate artifacts + * have been found within the build configuration. + * + * @since 2.10 + */ + // TODO: This can be removed if we change to full unique identifiers in EAR (next major version!) + @Parameter( defaultValue = "false", property = "maven.ear.duplicateArtifactsBreakTheBuild" ) + private boolean duplicateArtifactsBreakTheBuild; + + private void checkModuleUniqueness() + throws MojoExecutionException + { + ModuleIdentifierValidator miv = new ModuleIdentifierValidator( getModules() ); + miv.checkForDuplicateArtifacts(); + if ( miv.existDuplicateArtifacts() ) + { + Map<String, List<EarModule>> duplicateArtifacts = miv.getDuplicateArtifacts(); + for ( Entry<String, List<EarModule>> entry : duplicateArtifacts.entrySet() ) + { + getLog().warn( "The artifactId " + entry.getKey() + " exists more than once in the modules list." ); + for ( EarModule earModule : entry.getValue() ) + { + getLog().warn( " --> " + earModule.getArtifact().getId() + " (" + earModule.getType() + ")" ); + } + } + + getLog().warn( "HINT: This can be simply solved by using the <fileNameMapping>full</fileNameMapping>" ); + + if ( duplicateArtifactsBreakTheBuild ) + { + // CHECKSTYLE_OFF: LineLength + throw new MojoExecutionException( + "The build contains duplicate artifacts which result in unpredictable ear content." ); + // CHECKSTYLE_ON: LineLength + } + } + + } + + /** {@inheritDoc} */ + public void execute() + throws MojoExecutionException, MojoFailureException + { + // Initializes ear modules + super.execute(); + + zipArchiver.setUseJvmChmod( useJvmChmod ); + zipUnArchiver.setUseJvmChmod( useJvmChmod ); + + final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion( version ); + + // Initializes unpack types + List<String> unpackTypesList = createUnpackList(); + + // Copy modules + copyModules( javaEEVersion, unpackTypesList ); + + // Copy source files + try + { + File earSourceDir = earSourceDirectory; + if ( earSourceDir.exists() ) + { + getLog().info( "Copy ear sources to " + getWorkDirectory().getAbsolutePath() ); + String[] fileNames = getEarFiles( earSourceDir ); + for ( String fileName : fileNames ) + { + copyFile( new File( earSourceDir, fileName ), new File( getWorkDirectory(), fileName ) ); + } + } + + if ( applicationXml != null && !"".equals( applicationXml ) ) + { + // rename to application.xml + getLog().info( "Including custom application.xml[" + applicationXml + "]" ); + File metaInfDir = new File( getWorkDirectory(), META_INF ); + copyFile( new File( applicationXml ), new File( metaInfDir, "/application.xml" ) ); + } + + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Error copying EAR sources", e ); + } + catch ( MavenFilteringException e ) + { + throw new MojoExecutionException( "Error filtering EAR sources", e ); + } + + // Check if deployment descriptor is there + File ddFile = new File( getWorkDirectory(), APPLICATION_XML_URI ); + if ( !ddFile.exists() && ( javaEEVersion.lt( JavaEEVersion.FIVE ) ) ) + { + // CHECKSTYLE_OFF: LineLength + throw new MojoExecutionException( "Deployment descriptor: " + ddFile.getAbsolutePath() + " does not exist." ); + // CHECKSTYLE_ON: LineLength + } + + try + { + File earFile = getEarFile( outputDirectory, finalName, classifier ); + final MavenArchiver archiver = new EarMavenArchiver( getModules() ); + final JarArchiver theJarArchiver = getJarArchiver(); + getLog().debug( "Jar archiver implementation [" + theJarArchiver.getClass().getName() + "]" ); + archiver.setArchiver( theJarArchiver ); + archiver.setOutputFile( earFile ); + + // Include custom manifest if necessary + includeCustomManifestFile(); + + getLog().debug( "Excluding " + Arrays.asList( getPackagingExcludes() ) + " from the generated EAR." ); + getLog().debug( "Including " + Arrays.asList( getPackagingIncludes() ) + " in the generated EAR." ); + + archiver.getArchiver().addDirectory( getWorkDirectory(), getPackagingIncludes(), getPackagingExcludes() ); + archiver.createArchive( session, getProject(), archive ); + + if ( classifier != null ) + { + projectHelper.attachArtifact( getProject(), "ear", classifier, earFile ); + } + else + { + getProject().getArtifact().setFile( earFile ); + } + } + catch ( Exception e ) + { + throw new MojoExecutionException( "Error assembling EAR", e ); + } + } + + private void copyModules( final JavaEEVersion javaEEVersion, List<String> unpackTypesList ) + throws MojoExecutionException, MojoFailureException + { + try + { + // TODO: With the next major release the modules + // should be identified by a unique id instead of the + // the artifactId's only which means this + // check can be removed. + // http://jira.codehaus.org/browse/MEAR-209 + checkModuleUniqueness(); + + for ( EarModule module : getModules() ) + { + final File sourceFile = module.getArtifact().getFile(); + final File destinationFile = buildDestinationFile( getWorkDirectory(), module.getUri() ); + if ( !sourceFile.isFile() ) + { + throw new MojoExecutionException( "Cannot copy a directory: " + sourceFile.getAbsolutePath() + + "; Did you package/install " + module.getArtifact() + "?" ); + } + + if ( destinationFile.getCanonicalPath().equals( sourceFile.getCanonicalPath() ) ) + { + getLog().info( "Skipping artifact [" + module + "], as it already exists at [" + module.getUri() + + "]" ); + continue; + } + + // If the module is within the unpack list, make sure that no unpack wasn't forced (null or true) + // If the module is not in the unpack list, it should be true + // CHECKSTYLE_OFF: LineLength + if ( ( unpackTypesList.contains( module.getType() ) && ( module.shouldUnpack() == null || module.shouldUnpack() ) ) + || ( module.shouldUnpack() != null && module.shouldUnpack() ) ) + // CHECKSTYLE_ON: LineLength + { + getLog().info( "Copying artifact [" + module + "] to [" + module.getUri() + "] (unpacked)" ); + // Make sure that the destination is a directory to avoid plexus nasty stuff :) + destinationFile.mkdirs(); + unpack( sourceFile, destinationFile ); + + if ( skinnyWars && module.changeManifestClasspath() ) + { + changeManifestClasspath( module, destinationFile, javaEEVersion ); + } + } + else + { + if ( sourceFile.lastModified() > destinationFile.lastModified() ) + { + getLog().info( "Copying artifact [" + module + "] to [" + module.getUri() + "]" ); + FileUtils.copyFile( sourceFile, destinationFile ); + + if ( skinnyWars && module.changeManifestClasspath() ) + { + changeManifestClasspath( module, destinationFile, javaEEVersion ); + } + } + else + { + getLog().debug( "Skipping artifact [" + module + "], as it is already up to date at [" + + module.getUri() + "]" ); + } + } + } + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Error copying EAR modules", e ); + } + catch ( ArchiverException e ) + { + throw new MojoExecutionException( "Error unpacking EAR modules", e ); + } + catch ( NoSuchArchiverException e ) + { + throw new MojoExecutionException( "No Archiver found for EAR modules", e ); + } + } + + private List<String> createUnpackList() + throws MojoExecutionException + { + List<String> unpackTypesList = new ArrayList<String>(); + if ( unpackTypes != null ) + { + unpackTypesList = Arrays.asList( unpackTypes.split( "," ) ); + for ( String type : unpackTypesList ) + { + if ( !EarModuleFactory.STANDARD_ARTIFACT_TYPE.contains( type ) ) + { + throw new MojoExecutionException( "Invalid type [" + type + "] supported types are " + + EarModuleFactory.STANDARD_ARTIFACT_TYPE ); + } + } + getLog().debug( "Initialized unpack types " + unpackTypesList ); + } + return unpackTypesList; + } + + /** + * @return {@link #applicationXml} + */ + public String getApplicationXml() + { + return applicationXml; + } + + /** + * @param applicationXml {@link #applicationXml} + */ + public void setApplicationXml( String applicationXml ) + { + this.applicationXml = applicationXml; + } + + /** + * Returns a string array of the excludes to be used when assembling/copying the ear. + * + * @return an array of tokens to exclude + */ + protected String[] getExcludes() + { + List<String> excludeList = new ArrayList<String>( FileUtils.getDefaultExcludesAsList() ); + if ( earSourceExcludes != null && !"".equals( earSourceExcludes ) ) + { + excludeList.addAll( Arrays.asList( StringUtils.split( earSourceExcludes, "," ) ) ); + } + + // if applicationXml is specified, omit the one in the source directory + if ( getApplicationXml() != null && !"".equals( getApplicationXml() ) ) + { + excludeList.add( "**/" + META_INF + "/application.xml" ); + } + + return excludeList.toArray( new String[excludeList.size()] ); + } + + /** + * Returns a string array of the includes to be used when assembling/copying the ear. + * + * @return an array of tokens to include + */ + protected String[] getIncludes() + { + return StringUtils.split( StringUtils.defaultString( earSourceIncludes ), "," ); + } + + /** + * @return The array with the packaging excludes. + */ + public String[] getPackagingExcludes() + { + if ( StringUtils.isEmpty( packagingExcludes ) ) + { + return new String[0]; + } + else + { + return StringUtils.split( packagingExcludes, "," ); + } + } + + /** + * @param packagingExcludes {@link #packagingExcludes} + */ + public void setPackagingExcludes( String packagingExcludes ) + { + this.packagingExcludes = packagingExcludes; + } + + /** + * @return The arrays with the includes. + */ + public String[] getPackagingIncludes() + { + if ( StringUtils.isEmpty( packagingIncludes ) ) + { + return new String[] { "**" }; + } + else + { + return StringUtils.split( packagingIncludes, "," ); + } + } + + /** + * @param packagingIncludes {@link #packagingIncludes} + */ + public void setPackagingIncludes( String packagingIncludes ) + { + this.packagingIncludes = packagingIncludes; + } + + private static File buildDestinationFile( File buildDir, String uri ) + { + return new File( buildDir, uri ); + } + + private void includeCustomManifestFile() + { + if ( manifestFile == null ) + { + manifestFile = new File( getWorkDirectory(), "META-INF/MANIFEST.MF" ); + } + + if ( !manifestFile.exists() ) + { + getLog().info( "Could not find manifest file: " + manifestFile + " - Generating one" ); + } + else + { + getLog().info( "Including custom manifest file [" + manifestFile + "]" ); + archive.setManifestFile( manifestFile ); + } + } + + /** + * Returns the EAR file to generate, based on an optional classifier. + * + * @param basedir the output directory + * @param finalName the name of the ear file + * @param classifier an optional classifier + * @return the EAR file to generate + */ + private static File getEarFile( String basedir, String finalName, String classifier ) + { + if ( classifier == null ) + { + classifier = ""; + } + else if ( classifier.trim().length() > 0 && !classifier.startsWith( "-" ) ) + { + classifier = "-" + classifier; + } + + return new File( basedir, finalName + classifier + ".ear" ); + } + + /** + * Returns a list of filenames that should be copied over to the destination directory. + * + * @param sourceDir the directory to be scanned + * @return the array of filenames, relative to the sourceDir + */ + private String[] getEarFiles( File sourceDir ) + { + DirectoryScanner scanner = new DirectoryScanner(); + scanner.setBasedir( sourceDir ); + scanner.setExcludes( getExcludes() ); + scanner.addDefaultExcludes(); + + scanner.setIncludes( getIncludes() ); + + scanner.scan(); + + return scanner.getIncludedFiles(); + } + + /** + * Unpacks the module into the EAR structure. + * + * @param source File to be unpacked. + * @param destDir Location where to put the unpacked files. + * @throws NoSuchArchiverException In case of we don't have an appropriate archiver. + * @throws IOException In case of a general IOException. + */ + public void unpack( File source, File destDir ) + throws NoSuchArchiverException, IOException + { + UnArchiver unArchiver = archiverManager.getUnArchiver( "zip" ); + unArchiver.setSourceFile( source ); + unArchiver.setDestDirectory( destDir ); + + // Extract the module + unArchiver.extract(); + } + + /** + * Returns the {@link JarArchiver} implementation used to package the EAR file. + * <p/> + * By default the archiver is obtained from the Plexus container. + * + * @return the archiver + */ + protected JarArchiver getJarArchiver() + { + return jarArchiver; + } + + private void copyFile( File source, File target ) + throws MavenFilteringException, IOException, MojoExecutionException + { + if ( filtering && !isNonFilteredExtension( source.getName() ) ) + { + // Silly that we have to do this ourselves + if ( target.getParentFile() != null && !target.getParentFile().exists() ) + { + target.getParentFile().mkdirs(); + } + + mavenFileFilter.copyFile( source, target, true, getFilterWrappers(), encoding ); + } + else + { + FileUtils.copyFile( source, target ); + } + } + + /** + * @param fileName The name of the file which should be checked. + * @return {@code true} if the name is part of the non filtered extensions {@code false} otherwise. + */ + public boolean isNonFilteredExtension( String fileName ) + { + return !mavenResourcesFiltering.filteredFileExtension( fileName, nonFilteredFileExtensions ); + } + + private List<FileUtils.FilterWrapper> getFilterWrappers() + throws MojoExecutionException + { + if ( filterWrappers == null ) + { + try + { + MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution(); + mavenResourcesExecution.setMavenProject( getProject() ); + mavenResourcesExecution.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath ); + mavenResourcesExecution.setFilters( filters ); + mavenResourcesExecution.setEscapeString( escapeString ); + + filterWrappers = mavenFileFilter.getDefaultFilterWrappers( mavenResourcesExecution ); + } + catch ( MavenFilteringException e ) + { + getLog().error( "Fail to build filtering wrappers " + e.getMessage() ); + throw new MojoExecutionException( e.getMessage(), e ); + } + } + return filterWrappers; + } + + private void changeManifestClasspath( EarModule module, File original, JavaEEVersion javaEEVersion ) + throws MojoFailureException + { + try + { + File workDirectory; + + // Handle the case that the destination might be a directory (project-038) + if ( original.isFile() ) + { + // Create a temporary work directory + // MEAR-167 use uri as directory to prevent merging of artifacts with the same artifactId + workDirectory = new File( new File( getTempFolder(), "temp" ), module.getUri() ); + workDirectory.mkdirs(); + getLog().debug( "Created a temporary work directory: " + workDirectory.getAbsolutePath() ); + + // Unpack the archive to a temporary work directory + zipUnArchiver.setSourceFile( original ); + zipUnArchiver.setDestDirectory( workDirectory ); + zipUnArchiver.extract(); + } + else + { + workDirectory = original; + } + + // Create a META-INF/MANIFEST.MF file if it doesn't exist (project-038) + File metaInfDirectory = new File( workDirectory, "META-INF" ); + boolean newMetaInfCreated = metaInfDirectory.mkdirs(); + if ( newMetaInfCreated ) + { + // CHECKSTYLE_OFF: LineLength + getLog().debug( "This project did not have a META-INF directory before, so a new directory was created." ); + // CHECKSTYLE_ON: LineLength + } + File newCreatedManifestFile = new File( metaInfDirectory, "MANIFEST.MF" ); + boolean newManifestCreated = newCreatedManifestFile.createNewFile(); + if ( newManifestCreated ) + { + // CHECKSTYLE_OFF: LineLength + getLog().debug( "This project did not have a META-INF/MANIFEST.MF file before, so a new file was created." ); + // CHECKSTYLE_ON: LineLength + } + + // Read the manifest from disk + Manifest mf = new Manifest( new FileInputStream( newCreatedManifestFile ) ); + Attribute classPath = mf.getMainSection().getAttribute( "Class-Path" ); + List<String> classPathElements = new ArrayList<String>(); + + if ( classPath != null ) + { + classPathElements.addAll( Arrays.asList( classPath.getValue().split( " " ) ) ); + } + else + { + classPath = new Attribute( "Class-Path", "" ); + } + + // Modify the classpath entries in the manifest + for ( EarModule o : getModules() ) + { + if ( o instanceof JarModule ) + { + JarModule jm = (JarModule) o; + + if ( module.getLibDir() != null ) + { + // MEAR-189: + // We use the original name, cause in case of fileNameMapping to no-version/full + // we could not not delete it and it will end up in the resulting EAR and the WAR + // will not be cleaned up. + File artifact = + new File( new File( workDirectory, module.getLibDir() ), jm.getOriginalBundleFileName() ); + + if ( artifact.exists() ) + { + getLog().debug( " -> Artifact to delete: " + artifact ); + if ( !artifact.delete() ) + { + getLog().error( "Could not delete '" + artifact + "'" ); + } + } + } + + if ( classPathElements.contains( jm.getBundleFileName() ) ) + { + classPathElements.set( classPathElements.indexOf( jm.getBundleFileName() ), jm.getUri() ); + } + else + { + if ( !skipClassPathModification ) + { + classPathElements.add( jm.getUri() ); + } + else + { + if ( javaEEVersion.lt( JavaEEVersion.FIVE ) || defaultLibBundleDir == null ) + { + classPathElements.add( jm.getUri() ); + } + } + } + } + } + classPath.setValue( StringUtils.join( classPathElements.iterator(), " " ) ); + mf.getMainSection().addConfiguredAttribute( classPath ); + + // Write the manifest to disk + PrintWriter pw = new PrintWriter( newCreatedManifestFile ); + mf.write( pw ); + pw.close(); + + if ( original.isFile() ) + { + // Pack up the archive again from the work directory + if ( !original.delete() ) + { + getLog().error( "Could not delete original artifact file " + original ); + } + + getLog().debug( "Zipping module" ); + zipArchiver.setDestFile( original ); + zipArchiver.addDirectory( workDirectory ); + zipArchiver.createArchive(); + } + } + catch ( ManifestException e ) + { + throw new MojoFailureException( e.getMessage() ); + } + catch ( ZipException e ) + { + throw new MojoFailureException( e.getMessage() ); + } + catch ( IOException e ) + { + throw new MojoFailureException( e.getMessage() ); + } + catch ( ArchiverException e ) + { + throw new MojoFailureException( e.getMessage() ); + } + } +}
Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarPluginException.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarPluginException.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarPluginException.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EarPluginException.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,68 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * The base exception of the EAR plugin. + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: EarPluginException.java 1645331 2014-12-13 17:31:09Z khmarbaise $ + */ +public class EarPluginException + extends Exception +{ + + /** + * + */ + private static final long serialVersionUID = -5540929953103327928L; + + /** + * Create an instance. + */ + public EarPluginException() + { + } + + /** + * @param message The message for the exception. + */ + public EarPluginException( String message ) + { + super( message ); + } + + /** + * @param cause {@link Throwable} + */ + public EarPluginException( Throwable cause ) + { + super( cause ); + } + + /** + * @param message The message to emit. + * @param cause {@link Throwable} + */ + public EarPluginException( String message, Throwable cause ) + { + super( message, cause ); + } +} Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbClientModule.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbClientModule.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbClientModule.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbClientModule.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,58 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.artifact.Artifact; + +/** + * The {@link EarModule} implementation for an ejb client module. + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: EjbClientModule.java 1645331 2014-12-13 17:31:09Z khmarbaise $ + */ +public class EjbClientModule + extends JarModule +{ + + /** + * Create an instance. + */ + public EjbClientModule() + { + super(); + } + + /** + * @param a {@link Artifact} + * @param defaultLibBundleDir The default lib bundle directory. + */ + public EjbClientModule( Artifact a, String defaultLibBundleDir ) + { + super( a, defaultLibBundleDir, Boolean.FALSE ); + } + + /** + * {@inheritDoc} + */ + public String getType() + { + return "ejb-client"; + } +} Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbModule.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbModule.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbModule.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbModule.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,73 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.artifact.Artifact; +import org.codehaus.plexus.util.xml.XMLWriter; + +/** + * The {@link EarModule} implementation for an EJB module. + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: EjbModule.java 1645331 2014-12-13 17:31:09Z khmarbaise $ + */ +public class EjbModule + extends AbstractEarModule +{ + private static final String EJB_MODULE = "ejb"; + + /** + * Create an instance. + */ + public EjbModule() + { + } + + /** + * @param a {@link Artifact} + */ + public EjbModule( Artifact a ) + { + super( a ); + } + + /** + * {@inheritDoc} + */ + public void appendModule( XMLWriter writer, String version, Boolean generateId ) + { + startModuleElement( writer, generateId ); + writer.startElement( EJB_MODULE ); + writer.writeText( getUri() ); + writer.endElement(); + + writeAltDeploymentDescriptor( writer, version ); + + writer.endElement(); + } + + /** + * {@inheritDoc} + */ + public String getType() + { + return EJB_MODULE; + } +} Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbRef.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbRef.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbRef.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EjbRef.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,173 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.xml.XMLWriter; + +/** + * Representation of {@code ejb-ref} element in {@code application.xml} file. + * + * @author Karl Heinz Marbaise + * @since 2.10 + */ +public class EjbRef +{ + static final String DESCRIPTION = "description"; + + static final String EJB_REF = "ejb-ref"; + + static final String EJB_NAME = "ejb-ref-name"; + + static final String EJB_TYPE = "ejb-ref-type"; + + static final String EJB_LOOKUP_NAME = "lookup-name"; + + private final String description; + + private String name; + + private String type; + + private String lookupName; + + /** + * @param description The ejb-ref description. + * @param name The ejb-ref-name. + * @param type The ejb-ref-type + * @param lookupName The lookupname. + */ + public EjbRef( String description, String name, String type, String lookupName ) + { + if ( StringUtils.isEmpty( name ) ) + { + throw new IllegalArgumentException( EJB_NAME + " in " + EJB_REF + " element cannot be null." ); + } + else if ( StringUtils.isEmpty( type ) && StringUtils.isEmpty( lookupName ) ) + { + throw new IllegalArgumentException( EJB_TYPE + " in " + EJB_REF + " element cannot be null if no " + + EJB_LOOKUP_NAME + " was specified." ); + + } + + this.description = description; + this.name = name; + this.type = type; + this.lookupName = lookupName; + + } + + /** + * Appends the <tt>XML</tt> representation of this env-entry. + * + * @param writer the writer to use + */ + public void appendEjbRefEntry( XMLWriter writer ) + { + writer.startElement( EJB_REF ); + + // description + if ( getDescription() != null ) + { + doWriteElement( writer, DESCRIPTION, getDescription() ); + } + + // ejb name + doWriteElement( writer, EJB_NAME, getName() ); + + // ejb-type + if ( getType() != null ) + { + doWriteElement( writer, EJB_TYPE, getType() ); + } + + // lookup-name + if ( getLookupName() != null ) + { + doWriteElement( writer, EJB_LOOKUP_NAME, getLookupName() ); + } + + // end of ejb-ref + writer.endElement(); + } + + private void doWriteElement( XMLWriter writer, String element, String text ) + { + writer.startElement( element ); + writer.writeText( text ); + writer.endElement(); + } + + /** + * @return {@link #name} + */ + public String getName() + { + return name; + } + + /** + * @param name {@link #name} + */ + public void setName( String name ) + { + this.name = name; + } + + /** + * @return {@link #type} + */ + public String getType() + { + return type; + } + + /** + * @param type {@link #type} + */ + public void setType( String type ) + { + this.type = type; + } + + /** + * @return {@link #lookupName} + */ + public String getLookupName() + { + return lookupName; + } + + /** + * @param lookupName {@link #lookupName} + */ + public void setLookupName( String lookupName ) + { + this.lookupName = lookupName; + } + + /** + * @return {@link #description} + */ + public String getDescription() + { + return description; + } +} Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EnvEntry.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EnvEntry.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EnvEntry.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/EnvEntry.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,138 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.xml.XMLWriter; + +/** + * The representation of a env-entry entry within an application.xml file. + * + * @author Jim Brownfield based on code by <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: EnvEntry.java 1648055 2014-12-27 14:59:45Z khmarbaise $ + */ +class EnvEntry +{ + + static final String ENV_ENTRY = "env-entry"; + + static final String DESCRIPTION = "description"; + + static final String ENV_ENTRY_NAME = "env-entry-name"; + + static final String ENV_ENTRY_TYPE = "env-entry-type"; + + static final String ENV_ENTRY_VALUE = "env-entry-value"; + + private final String description; + + private final String name; + + private final String type; + + private final String value; + + public EnvEntry( String description, String name, String type, String value ) + { + if ( StringUtils.isEmpty( name ) ) + { + throw new IllegalArgumentException( ENV_ENTRY_NAME + " in " + ENV_ENTRY + " element cannot be null." ); + } + else if ( StringUtils.isEmpty( type ) && StringUtils.isEmpty( value ) ) + { + throw new IllegalArgumentException( ENV_ENTRY_TYPE + " in " + ENV_ENTRY + " element cannot be null if no " + + ENV_ENTRY_VALUE + " was specified." ); + + } + + this.description = description; + this.name = name; + this.type = type; + this.value = value; + } + + public String getDescription() + { + return description; + } + + public String getName() + { + return name; + } + + public String getType() + { + return type; + } + + public String getValue() + { + return value; + } + + /** + * Appends the <tt>XML</tt> representation of this env-entry. + * + * @param writer the writer to use + */ + public void appendEnvEntry( XMLWriter writer ) + { + System.out.println( "appendEnvEntry()" ); + writer.startElement( ENV_ENTRY ); + + // description + if ( getDescription() != null ) + { + doWriteElement( writer, DESCRIPTION, getDescription() ); + } + + // env entry name + doWriteElement( writer, ENV_ENTRY_NAME, getName() ); + + // env entry type + if ( getType() != null ) + { + doWriteElement( writer, ENV_ENTRY_TYPE, getType() ); + } + + // env entry value + if ( getValue() != null ) + { + doWriteElement( writer, ENV_ENTRY_VALUE, getValue() ); + } + + // end of env-entry + writer.endElement(); + } + + private void doWriteElement( XMLWriter writer, String element, String text ) + { + writer.startElement( element ); + writer.writeText( text ); + writer.endElement(); + } + + public String toString() + { + return "env-entry [name=" + getName() + ", type=" + getType() + ", value=" + getValue() + "]"; + } + +} \ No newline at end of file Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/GenerateApplicationXmlMojo.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/GenerateApplicationXmlMojo.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/GenerateApplicationXmlMojo.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/GenerateApplicationXmlMojo.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,462 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.plugins.ear.util.JavaEEVersion; +import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.codehaus.plexus.interpolation.InterpolationException; +import org.codehaus.plexus.interpolation.Interpolator; +import org.codehaus.plexus.interpolation.MapBasedValueSource; +import org.codehaus.plexus.interpolation.StringSearchInterpolator; +import org.codehaus.plexus.interpolation.ValueSource; +import org.codehaus.plexus.util.FileUtils; + +/** + * Generates the EAR deployment descriptor file(s). + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: GenerateApplicationXmlMojo.java 1713543 2015-11-09 21:32:15Z khmarbaise $ + */ +// CHECKSTYLE_OFF: LineLength +@Mojo( name = "generate-application-xml", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST ) +// CHECKSTYLE_ON: LineLength +public class GenerateApplicationXmlMojo + extends AbstractEarMojo +{ + + /** + * The DEFAULT library folder. + */ + public static final String DEFAULT = "DEFAULT"; + + /** + * The empty folder. + */ + public static final String EMPTY = "EMPTY"; + + /** + * The NONE not existent folder. + */ + public static final String NONE = "NONE"; + + /** + * Whether the application.xml should be generated or not. + */ + @Parameter( defaultValue = "true" ) + private Boolean generateApplicationXml = Boolean.TRUE; + + /** + * Whether a module ID should be generated if none is specified. + */ + @Parameter( defaultValue = "false" ) + private Boolean generateModuleId = Boolean.FALSE; + + /** + * Application name of the application to be used when the application.xml file is auto-generated. Since JavaEE6. + */ + @Parameter + private String applicationName; + + /** + * Display name of the application to be used when the application.xml file is auto-generated. + */ + @Parameter( defaultValue = "${project.artifactId}" ) + private String displayName; + + /** + * Description of the application to be used when the application.xml file is auto-generated. + */ + @Parameter( defaultValue = "${project.description}" ) + private String description; + + /** + * Defines how the <tt>library-directory</tt> element should be written in the application.xml file. + * <p/> + * Three special values can be set: + * <ul> + * <li><code>DEFAULT</code> (default) generates a <tt>library-directory</tt> element with the value of the + * <tt>defaultLibBundleDir</tt> parameter</li> + * <li><code>EMPTY</code> generates an empty <tt>library-directory</tt> element. Per spec, this disables the + * scanning of jar files in the <tt>lib</tt> directory of the ear file</li> + * <li><code>NONE</code> does not write the library-directory element at all. A corner case that can be used in + * Oracle Weblogic to delegate the classloading to the container</li> + * </ul> + * <p/> + * Since JavaEE5. + */ + @Parameter( defaultValue = DEFAULT ) + private String libraryDirectoryMode; + + /** + * Defines the value of the initialize in order element to be used when the application.xml file is auto-generated. + * When set to true, modules must be initialized in the order they're listed in this deployment descriptor, with the + * exception of application client modules, which can be initialized in any order. If initialize-in-order is not set + * or set to false, the order of initialization is unspecified and may be product-dependent. Since JavaEE6. + */ + @Parameter + private Boolean initializeInOrder; + + /** + * Defines the application id used when generating the deployment descriptor. + * + * @since 2.9 + */ + @Parameter + private String applicationId; + + /** + * The security-roles to be added to the auto-generated application.xml file. + */ + @Parameter + private PlexusConfiguration security; + + /** + * The env-entries to be added to the auto-generated application.xml file. Since JavaEE6. + */ + @Parameter( alias = "env-entries" ) + private PlexusConfiguration envEntries; + + /** + * The {@code ejb-ref} entries. + */ + @Parameter( alias = "ejb-refs" ) + private PlexusConfiguration ejbRefs; + + /** + * {@inheritDoc} + */ + public void execute() + throws MojoExecutionException, MojoFailureException + { + // Initializes ear modules + super.execute(); + + // Handle application.xml + if ( !generateApplicationXml ) + { + getLog().debug( "Generation of application.xml is disabled" ); + } + else + { + final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion( version ); + + // Generate deployment descriptor and copy it to the build directory + getLog().info( "Generating application.xml" ); + try + { + generateStandardDeploymentDescriptor( javaEEVersion ); + } + catch ( EarPluginException e ) + { + throw new MojoExecutionException( "Failed to generate application.xml", e ); + } + + try + { + FileUtils.copyFileToDirectory( new File( generatedDescriptorLocation, "application.xml" ), + new File( getWorkDirectory(), "META-INF" ) ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Unable to copy application.xml to final destination", e ); + } + } + + // Handle jboss-app.xml + if ( getJbossConfiguration() == null ) + { + getLog().debug( "Generation of jboss-app.xml is disabled" ); + } + else + { + // Generate deployment descriptor and copy it to the build directory + getLog().info( "Generating jboss-app.xml" ); + try + { + generateJbossDeploymentDescriptor(); + } + catch ( EarPluginException e ) + { + throw new MojoExecutionException( "Failed to generate jboss-app.xml", e ); + } + + try + { + FileUtils.copyFileToDirectory( new File( generatedDescriptorLocation, "jboss-app.xml" ), + new File( getWorkDirectory(), "META-INF" ) ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Unable to copy jboss-app.xml to final destination", e ); + } + } + } + + /** + * Generates the deployment descriptor. + * + * @param javaEEVersion {@link JavaEEVersion} + * @throws EarPluginException if the configuration is invalid + */ + protected void generateStandardDeploymentDescriptor( JavaEEVersion javaEEVersion ) + throws EarPluginException + { + File outputDir = new File( generatedDescriptorLocation ); + if ( !outputDir.exists() ) + { + outputDir.mkdirs(); + } + + File descriptor = new File( outputDir, "application.xml" ); + + final ApplicationXmlWriter writer = new ApplicationXmlWriter( javaEEVersion, encoding, generateModuleId ); + final ApplicationXmlWriterContext context = + new ApplicationXmlWriterContext( descriptor, getModules(), buildSecurityRoles(), buildEnvEntries(), + buildEjbEntries(), displayName, description, getActualLibraryDirectory(), + applicationName, initializeInOrder ).setApplicationId( applicationId ); + writer.write( context ); + } + + /** + * Generates the jboss deployment descriptor. + * + * @throws EarPluginException if the configuration is invalid + */ + protected void generateJbossDeploymentDescriptor() + throws EarPluginException + { + File outputDir = new File( generatedDescriptorLocation ); + if ( !outputDir.exists() ) + { + outputDir.mkdirs(); + } + + File descriptor = new File( outputDir, "jboss-app.xml" ); + + JbossAppXmlWriter writer = new JbossAppXmlWriter( encoding ); + writer.write( descriptor, getJbossConfiguration(), getModules() ); + } + + /** + * Builds the security roles based on the configuration. + * + * @return a list of SecurityRole object(s) + * @throws EarPluginException if the configuration is invalid + */ + private List<SecurityRole> buildSecurityRoles() + throws EarPluginException + { + final List<SecurityRole> result = new ArrayList<SecurityRole>(); + if ( security == null ) + { + return result; + } + final PlexusConfiguration[] securityRoles = security.getChildren( SecurityRole.SECURITY_ROLE ); + + for ( PlexusConfiguration securityRole : securityRoles ) + { + final String id = securityRole.getAttribute( SecurityRole.ID_ATTRIBUTE ); + final String childRoleName = securityRole.getChild( SecurityRole.ROLE_NAME ).getValue(); + final String childRoleNameId = + securityRole.getChild( SecurityRole.ROLE_NAME ).getAttribute( SecurityRole.ID_ATTRIBUTE ); + final String childDescription = securityRole.getChild( SecurityRole.DESCRIPTION ).getValue(); + final String childDescriptionId = + securityRole.getChild( SecurityRole.DESCRIPTION ).getAttribute( SecurityRole.ID_ATTRIBUTE ); + + if ( childRoleName == null ) + { + throw new EarPluginException( "Invalid security-role configuration, role-name could not be null." ); + } + else + { + result.add( new SecurityRole( childRoleName, childRoleNameId, id, childDescription, + childDescriptionId ) ); + } + } + return result; + } + + /** + * This help method was needed otherwise the interpolate method of interpolator will make an empty string of a + * {@code null} element which results in supplemental elements for env-entry. + * + * @param interpolator The interpolator + * @param element The element + * @return The interpolated elements. + * @throws InterpolationException in case of an error. + */ + private String interpolate( Interpolator interpolator, String element ) + throws InterpolationException + { + if ( element == null ) + { + return element; + } + else + { + return interpolator.interpolate( element ); + } + } + + /** + * Builds the env-entries based on the configuration. + * + * @return a list of EnvEntry object(s) + * @throws EarPluginException if the configuration is invalid + */ + private List<EnvEntry> buildEnvEntries() + throws EarPluginException + { + final List<EnvEntry> result = new ArrayList<EnvEntry>(); + if ( envEntries == null ) + { + return result; + } + try + { + StringSearchInterpolator ssi = new StringSearchInterpolator(); + ValueSource vs = new MapBasedValueSource( project.getProperties() ); + ssi.addValueSource( vs ); + + final PlexusConfiguration[] allEnvEntries = envEntries.getChildren( EnvEntry.ENV_ENTRY ); + + for ( PlexusConfiguration envEntry : allEnvEntries ) + { + // CHECKSTYLE_OFF: LineLength + final String childDescription = + interpolate( ssi, envEntry.getChild( EnvEntry.DESCRIPTION ).getValue() ); + final String childEnvEntryName = + interpolate( ssi, envEntry.getChild( EnvEntry.ENV_ENTRY_NAME ).getValue() ); + final String childEnvEntryType = + interpolate( ssi, envEntry.getChild( EnvEntry.ENV_ENTRY_TYPE ).getValue() ); + final String childEnvEntryValue = + interpolate( ssi, envEntry.getChild( EnvEntry.ENV_ENTRY_VALUE ).getValue() ); + // CHECKSTYLE_ON: LineLength + + try + { + result.add( new EnvEntry( childDescription, childEnvEntryName, childEnvEntryType, + childEnvEntryValue ) ); + } + catch ( IllegalArgumentException e ) + { + throw new EarPluginException( "Invalid env-entry [" + envEntry + "]", e ); + } + } + return result; + } + catch ( InterpolationException e ) + { + throw new EarPluginException( "Interpolation exception:", e ); + } + + } + + /** + * Builds the ejb-ref based on the configuration. + * + * @return a list of EjbRef object(s) + * @throws EarPluginException if the configuration is invalid + */ + private List<EjbRef> buildEjbEntries() + throws EarPluginException + { + final List<EjbRef> result = new ArrayList<EjbRef>(); + if ( ejbRefs == null ) + { + return result; + } + try + { + StringSearchInterpolator ssi = new StringSearchInterpolator(); + ValueSource vs = new MapBasedValueSource( project.getProperties() ); + ssi.addValueSource( vs ); + + final PlexusConfiguration[] allEjbEntries = ejbRefs.getChildren( EjbRef.EJB_REF ); + + for ( PlexusConfiguration ejbEntry : allEjbEntries ) + { + // CHECKSTYLE_OFF: LineLength + final String childDescription = + interpolate( ssi, ejbEntry.getChild( EnvEntry.DESCRIPTION ).getValue() ); + final String childEjbEntryName = interpolate( ssi, ejbEntry.getChild( EjbRef.EJB_NAME ).getValue() ); + final String childEjbEntryType = interpolate( ssi, ejbEntry.getChild( EjbRef.EJB_TYPE ).getValue() ); + final String childEjbLookupNameValue = + interpolate( ssi, ejbEntry.getChild( EjbRef.EJB_LOOKUP_NAME ).getValue() ); + // CHECKSTYLE_ON: LineLength + + try + { + result.add( new EjbRef( childDescription, childEjbEntryName, childEjbEntryType, + childEjbLookupNameValue ) ); + } + catch ( IllegalArgumentException e ) + { + throw new EarPluginException( "Invalid ejb-ref [" + ejbEntry + "]", e ); + } + } + return result; + } + catch ( InterpolationException e ) + { + throw new EarPluginException( "Interpolation exception:", e ); + } + + } + + /** + * Returns the value to use for the <tt>library-directory</tt> element, based on the library directory mode. + */ + private String getActualLibraryDirectory() + throws EarPluginException + { + final String mode = libraryDirectoryMode == null ? DEFAULT : libraryDirectoryMode.toUpperCase(); + + if ( DEFAULT.equals( mode ) ) + { + return defaultLibBundleDir; + } + else if ( EMPTY.equals( mode ) ) + { + return ""; + } + else if ( NONE.equals( mode ) ) + { + return null; + } + else + { + throw new EarPluginException( "Unsupported library directory mode [" + libraryDirectoryMode + + "] Supported modes " + ( Arrays.asList( DEFAULT, EMPTY, NONE ) ) ); + } + } +} \ No newline at end of file Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/HarModule.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/HarModule.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/HarModule.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/HarModule.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,79 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.artifact.Artifact; +import org.codehaus.plexus.util.xml.XMLWriter; + +/** + * The {@link EarModule} implementation for a JBoss Hibernate archive. + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: HarModule.java 1645331 2014-12-13 17:31:09Z khmarbaise $ + */ +public class HarModule + extends AbstractEarModule + implements JbossEarModule +{ + /** + * Create an instance. + */ + public HarModule() + { + } + + /** + * @param a {@link Artifact} + */ + public HarModule( Artifact a ) + { + super( a ); + } + + /** + * {@inheritDoc} + */ + public void appendModule( XMLWriter writer, String version, Boolean generateId ) + { + // No entry is generated by this artifact ; it should be + // defined in the jboss-app.xml. + // See http://docs.jboss.org/jbossas/getting_started/v4/html/hibernate.html + } + + /** + * {@inheritDoc} + */ + public void appendJbossModule( XMLWriter writer, String version ) + { + writer.startElement( MODULE_ELEMENT ); + writer.startElement( "har" ); + writer.writeText( getUri() ); + writer.endElement(); + writer.endElement(); + } + + /** + * {@inheritDoc} + */ + public String getType() + { + return "har"; + } +} Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JarModule.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JarModule.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JarModule.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JarModule.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,123 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.util.xml.XMLWriter; + +import java.util.Set; + +/** + * The {@link EarModule} implementation for a non J2EE module such as third party libraries. + * <p/> + * Such module is not incorporated in the generated <tt>application.xml<tt> + * but some application servers support it. To include it in the generated + * deployment descriptor anyway, set the <tt>includeInApplicationXml</tt> boolean flag. + * <p/> + * This class deprecates {@link org.apache.maven.plugins.ear.JavaModule}. + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: JarModule.java 1648046 2014-12-27 11:07:02Z khmarbaise $ + */ +public class JarModule + extends AbstractEarModule +{ + private Boolean includeInApplicationXml = Boolean.FALSE; + + /** + * Create an instance. + */ + public JarModule() + { + super(); + } + + /** + * @param a {@link Artifact} + * @param defaultLibBundleDir The default library bundle directory. + * @param includeInApplicationXml Include the application xml or not. + */ + public JarModule( Artifact a, String defaultLibBundleDir, Boolean includeInApplicationXml ) + { + super( a ); + setLibBundleDir( defaultLibBundleDir ); + this.includeInApplicationXml = includeInApplicationXml; + + } + + /** + * {@inheritDoc} + */ + public void appendModule( XMLWriter writer, String version, Boolean generateId ) + { + // Generates an entry in the application.xml only if + // includeInApplicationXml is set + if ( includeInApplicationXml ) + { + startModuleElement( writer, generateId ); + writer.startElement( JAVA_MODULE ); + writer.writeText( getUri() ); + writer.endElement(); + + writeAltDeploymentDescriptor( writer, version ); + + writer.endElement(); + } + } + + /** + * {@inheritDoc} + */ + public void resolveArtifact( Set<Artifact> artifacts ) + throws EarPluginException, MojoFailureException + { + // Let's resolve the artifact + super.resolveArtifact( artifacts ); + + // If the defaultLibBundleDir is set and no bundle dir is + // set, set the default as bundle dir + setLibBundleDir( earExecutionContext.getDefaultLibBundleDir() ); + } + + /** + * {@inheritDoc} + */ + public String getType() + { + return "jar"; + } + + private void setLibBundleDir( String defaultLibBundleDir ) + { + if ( defaultLibBundleDir != null && bundleDir == null ) + { + this.bundleDir = defaultLibBundleDir; + } + } + + /** + * {@inheritDoc} + */ + public boolean changeManifestClasspath() + { + return false; + } +} Added: maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JbossAppXmlWriter.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JbossAppXmlWriter.java?rev=1755643&view=auto ============================================================================== --- maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JbossAppXmlWriter.java (added) +++ maven/plugins/trunk/maven-ear-plugin/src/main/java/org/apache/maven/plugins/ear/JbossAppXmlWriter.java Tue Aug 9 19:17:58 2016 @@ -0,0 +1,191 @@ +package org.apache.maven.plugins.ear; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.Writer; +import java.util.List; + +import org.codehaus.plexus.util.xml.XMLWriter; + +/** + * An <tt>XmlWriter</tt> based implementation used to generate a <tt>jboss-app.xml</tt> file + * + * @author <a href="[email protected]">Stephane Nicoll</a> + * @version $Id: JbossAppXmlWriter.java 1636449 2014-11-03 21:27:36Z khmarbaise $ + */ +final class JbossAppXmlWriter + extends AbstractXmlWriter +{ + + public static final String DOCTYPE_3_2 = "jboss-app PUBLIC\n" + "\t\"-//JBoss//DTD J2EE Application 1.3//EN\"\n" + + "\t\"http://www.jboss.org/j2ee/dtd/jboss-app_3_2.dtd\""; + + public static final String DOCTYPE_4 = "jboss-app PUBLIC\n" + "\t\"-//JBoss//DTD J2EE Application 1.4//EN\"\n" + + "\t\"http://www.jboss.org/j2ee/dtd/jboss-app_4_0.dtd\""; + + public static final String DOCTYPE_4_2 = "jboss-app PUBLIC\n" + "\t\"-//JBoss//DTD J2EE Application 4.2//EN\"\n" + + "\t\"http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd\""; + + public static final String DOCTYPE_5 = "jboss-app PUBLIC\n" + "\t\"-//JBoss//DTD Java EE Application 5.0//EN\"\n" + + "\t\"http://www.jboss.org/j2ee/dtd/jboss-app_5_0.dtd\""; + + private static final String JBOSS_APP_ELEMENT = "jboss-app"; + + JbossAppXmlWriter( String encoding ) + { + super( encoding ); + } + + public void write( File destinationFile, JbossConfiguration jbossConfiguration, List<EarModule> earModules ) + throws EarPluginException + { + final Writer w = initializeWriter( destinationFile ); + + XMLWriter writer; + if ( jbossConfiguration.isJbossThreeDotTwo() ) + { + writer = initializeXmlWriter( w, DOCTYPE_3_2 ); + } + else if ( jbossConfiguration.isJbossFour() ) + { + writer = initializeXmlWriter( w, DOCTYPE_4 ); + } + else if ( jbossConfiguration.isJbossFourDotTwo() ) + { + writer = initializeXmlWriter( w, DOCTYPE_4_2 ); + } + else + { + writer = initializeXmlWriter( w, DOCTYPE_5 ); + } + writer.startElement( JBOSS_APP_ELEMENT ); + + // Make sure to write the things in the right order so that the DTD validates + + // module-order (only available as from 4.2) + if ( jbossConfiguration.isJbossFourDotTwoOrHigher() && jbossConfiguration.getModuleOrder() != null ) + { + writer.startElement( JbossConfiguration.MODULE_ORDER ); + writer.writeText( jbossConfiguration.getModuleOrder() ); + writer.endElement(); + } + + // If JBoss 4, write the jboss4 specific stuff + if ( jbossConfiguration.isJbossFourOrHigher() ) + { + if ( jbossConfiguration.getSecurityDomain() != null ) + { + writer.startElement( JbossConfiguration.SECURITY_DOMAIN ); + writer.writeText( jbossConfiguration.getSecurityDomain() ); + writer.endElement(); + } + if ( jbossConfiguration.getUnauthenticatedPrincipal() != null ) + { + writer.startElement( JbossConfiguration.UNAUHTHENTICTED_PRINCIPAL ); + writer.writeText( jbossConfiguration.getUnauthenticatedPrincipal() ); + writer.endElement(); + } + } + + // classloader repository + // CHECKSTYLE_OFF: LineLength + if ( jbossConfiguration.getLoaderRepository() != null || jbossConfiguration.getLoaderRepositoryConfig() != null ) + // CHECKSTYLE_ON: LineLength + { + writer.startElement( JbossConfiguration.LOADER_REPOSITORY ); + + // classloader repository class + if ( jbossConfiguration.getLoaderRepositoryClass() != null ) + { + writer.addAttribute( JbossConfiguration.LOADER_REPOSITORY_CLASS_ATTRIBUTE, + jbossConfiguration.getLoaderRepositoryClass() ); + } + + // we don't need to write any text if only the loader repo configuration is changed + if ( jbossConfiguration.getLoaderRepository() != null ) + { + writer.writeText( jbossConfiguration.getLoaderRepository() ); + } + + // classloader configuration + if ( jbossConfiguration.getLoaderRepositoryConfig() != null ) + { + writer.startElement( JbossConfiguration.LOADER_REPOSITORY_CONFIG ); + + // classloader configuration parser + if ( jbossConfiguration.getConfigParserClass() != null ) + { + writer.addAttribute( JbossConfiguration.CONFIG_PARSER_CLASS_ATTRIBUTE, + jbossConfiguration.getConfigParserClass() ); + } + writer.writeText( jbossConfiguration.getLoaderRepositoryConfig() ); + writer.endElement(); + } + + writer.endElement(); + } + + // jmx name + if ( jbossConfiguration.getJmxName() != null ) + { + writer.startElement( JbossConfiguration.JMX_NAME ); + writer.writeText( jbossConfiguration.getJmxName() ); + writer.endElement(); + } + + // library-directory (only available as from 4.2) + if ( jbossConfiguration.isJbossFourDotTwoOrHigher() && jbossConfiguration.getLibraryDirectory() != null ) + { + writer.startElement( JbossConfiguration.LIBRARY_DIRECTORY ); + writer.writeText( jbossConfiguration.getLibraryDirectory() ); + writer.endElement(); + } + + // Modules + + List<String> dataSources = jbossConfiguration.getDataSources(); + // Write out data source modules first + if ( dataSources != null ) + { + for ( String dsPath : dataSources ) + { + writer.startElement( MODULE_ELEMENT ); + writer.startElement( SERVICE_ELEMENT ); + writer.writeText( dsPath ); + writer.endElement(); + writer.endElement(); + } + } + + // Write the JBoss specific modules + for ( EarModule earModule : earModules ) + { + if ( JbossEarModule.class.isInstance( earModule ) ) + { + JbossEarModule jbossEarModule = (JbossEarModule) earModule; + jbossEarModule.appendJbossModule( writer, jbossConfiguration.getVersion() ); + } + } + writer.endElement(); + + close( w ); + } +} \ No newline at end of file
