package org.codehaus.mojo.webstart; /* * 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.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.filter.AndArtifactFilter; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter; import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProjectHelper; import org.apache.maven.shared.utils.io.FileUtils; import org.codehaus.mojo.webstart.generator.ExtensionGenerator; import org.codehaus.mojo.webstart.generator.ExtensionGeneratorConfig; import org.codehaus.mojo.webstart.generator.Generator; import org.codehaus.mojo.webstart.generator.GeneratorConfig; import org.codehaus.mojo.webstart.generator.GeneratorTechnicalConfig; import org.codehaus.mojo.webstart.util.IOUtil; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; /** * @author <a href="[email protected]">Jerome Lacoste</a> * @version $Id$ * TODO how to propagate the -X argument to enable verbose? * TODO initialize the jnlp alias and dname.o from pom.artifactId and pom.organization.name */ public abstract class AbstractJnlpMojo extends AbstractBaseJnlpMojo { // ---------------------------------------------------------------------- // Constants // ---------------------------------------------------------------------- /** * Name of the built in jnlp template to use if none given. */ private static final String BUILT_IN_JNLP_TEMPLATE_FILENAME = "default-jnlp-template.vm"; /** * Name of the default jnlp template to use if user define it in the default template directory. */ private static final String JNLP_TEMPLATE_FILENAME = "template.vm"; /** * Name of the built in extension template to use if none is given. */ private static final String BUILT_IN_EXTENSION_TEMPLATE_FILENAME = "default-jnlp-extension-template.vm"; /** * Name of the default jnlp extension template to use if user define it in the default template directory. */ private static final String EXTENSION_TEMPLATE_FILENAME = "extension-template.vm"; private static final String JNLP_INF_APPLICATION_JNLP = "JNLP-INF/APPLICATION.JNLP"; // ---------------------------------------------------------------------- // Mojo Parameters // ---------------------------------------------------------------------- /** * Represents the configuration element that specifies which of the current * project's dependencies will be included or excluded from the resources element * in the generated JNLP file. */ public static class Dependencies { private List<String> includes; private List<String> excludes; public List<String> getIncludes() { return includes; } public void setIncludes( List<String> includes ) { this.includes = includes; } public List<String> getExcludes() { return excludes; } public void setExcludes( List<String> excludes ) { this.excludes = excludes; } } /** * Flag to create the archive or not. * * @since 1.0-beta-2 */ @Parameter( property = "jnlp.makeArchive", defaultValue = "true" ) private boolean makeArchive; /** * Flag to attach the archive or not to the project's build. * * @since 1.0-beta-2 */ @Parameter( property = "jnlp.attachArchive", defaultValue = "true" ) private boolean attachArchive; /** * The path of the archive to generate if {@link #makeArchive} flag is on. * * @since 1.0-beta-4 */ @Parameter( property = "jnlp.archive", defaultValue = "${project.build.directory}/${project.build.finalName}.zip" ) private File archive; /** * The jnlp configuration element. */ @Parameter private JnlpConfig jnlp; /** * [optional] extensions configuration. * * @since 1.0-beta-2 */ @Parameter private List<JnlpExtension> jnlpExtensions; /** * [optional] transitive dependencies filter - if omitted, the plugin will include all transitive dependencies. * Provided and test scope dependencies are always excluded. */ @Parameter private Dependencies dependencies; /** * A placeholder for an obsoleted configuration element. * <p> * This dummy parameter is here to force the plugin configuration to fail in case one * didn't properly migrate from 1.0-alpha-1 to 1.0-alpha-2 configuration. * <p> * It will be removed before 1.0. */ @Parameter private String keystore; /** */ @Parameter( defaultValue = "${basedir}", readonly = true, required = true ) private File basedir; /** * When set to true, this flag indicates that a version attribute should * be output in each of the jar resource elements in the generated * JNLP file. * <p> * <strong>Note: </strong> since version 1.0-beta-5 we use the version download protocol optimization (see * http://docs.oracle.com/javase/tutorial/deployment/deploymentInDepth/avoidingUnnecessaryUpdateChecks.html). */ @Parameter( property = "jnlp.outputJarVersions", defaultValue = "false" ) private boolean outputJarVersions; /** * Flag to skip dependencies (this can be usefull if you use a shaded jar). * * @since 1.0.0 */ @Parameter( property = "jnlp.skipDependencies", defaultValue = "false" ) private boolean skipDependencies; /** * Flag to add the jnlp file inside to main jar at {@code JNLP-INF/APPLICATION.JNLP} location. * * @since 1.0.0 */ @Parameter( defaultValue = "true" ) private boolean addApplicationFile; // ---------------------------------------------------------------------- // Components // ---------------------------------------------------------------------- /** * The project helper used to attach the artifact produced by this plugin to the project. */ @Component private MavenProjectHelper projectHelper; // ---------------------------------------------------------------------- // Fields // ---------------------------------------------------------------------- /** * the artifacts packaged in the webstart app */ private List<Artifact> packagedJnlpArtifacts = new ArrayList<>(); /** * the artifacts associated to each jnlp extension */ private Map<JnlpExtension, List<Artifact>> extensionsJnlpArtifacts = new HashMap<>(); private Artifact artifactWithMainClass; // ---------------------------------------------------------------------- // Mojo Implementation // ---------------------------------------------------------------------- @Override public void execute() throws MojoExecutionException { boolean withExtensions = CollectionUtils.isNotEmpty( jnlpExtensions ); if ( withExtensions ) { prepareExtensions(); findDefaultJnlpExtensionTemplateURL(); } checkInput(); getLog().debug( "using work directory " + getWorkDirectory() ); getLog().debug( "using library directory " + getLibDirectory() ); IOUtil ioUtil = getIoUtil(); // --- // prepare layout // --- ioUtil.makeDirectoryIfNecessary( getWorkDirectory() ); ioUtil.makeDirectoryIfNecessary( getLibDirectory() ); try { ioUtil.copyResources( getResourcesDirectory(), getWorkDirectory() ); artifactWithMainClass = null; processDependencies(); if ( jnlp.isRequireMainClass() && artifactWithMainClass == null ) { throw new MojoExecutionException( "didn't find artifact with main class: " + jnlp.getMainClass() + ". Did you specify it? " ); } if ( withExtensions ) { processExtensionsDependencies(); } // --- // Process native libs (FIXME) // --- processNativeLibs(); if ( ( isPack200() || getSign() != null ) && getLog().isDebugEnabled() ) { logCollection( "Some dependencies may be skipped. Here's the list of the artifacts that should be signed/packed: ", getModifiedJnlpArtifacts() ); } // --- // Process collected jars // --- signOrRenameJars(); // --- // Generate jnlp file // --- generateJnlpFile( getWorkDirectory() ); // --- // Generate jnlp extension files // --- if ( withExtensions ) { generateJnlpExtensionsFile( getWorkDirectory() ); } // --- // Generate archive file if required // --- if ( makeArchive ) { // package the zip. Note this is very simple. Look at the JarMojo which does more things. // we should perhaps package as a war when inside a project with war packaging ? ioUtil.makeDirectoryIfNecessary( archive.getParentFile() ); ioUtil.deleteFile( archive ); verboseLog( "Will create archive at location: " + archive ); ioUtil.createArchive( getWorkDirectory(), archive ); if ( attachArchive ) { // maven 2 version 2.0.1 method projectHelper.attachArtifact( getProject(), "zip", archive ); } } } catch ( MojoExecutionException e ) { throw e; } catch ( Exception e ) { throw new MojoExecutionException( "Failure to run the plugin: ", e ); } } // ---------------------------------------------------------------------- // Protected Methods // ---------------------------------------------------------------------- protected JnlpConfig getJnlp() { return jnlp; } protected Dependencies getDependencies() { return this.dependencies; } // ---------------------------------------------------------------------- // Private Methods // ---------------------------------------------------------------------- void checkJnlpConfig() throws MojoExecutionException { if ( jnlp == null ) { throw new MojoExecutionException( "jnlp must be set to generate config!" ); } JnlpFileType type = jnlp.getType(); if ( type == null ) { throw new MojoExecutionException( "jnlp must define a default jnlp type file to generate (among " + Arrays.toString( JnlpFileType.values() ) + " )." ); } if ( !type.isRequireMainClass() && StringUtils.isNotBlank( jnlp.getMainClass() ) ) { getLog().warn( "Jnlp file of type '" + type + "' does not support mainClass, value will not be accessible in template." ); jnlp.setMainClass( null ); addApplicationFile = false; } } /** * Detects improper includes/excludes configuration. * * @throws MojoExecutionException if at least one of the specified includes or excludes matches no artifact, * false otherwise */ void checkDependencies() throws MojoExecutionException { if ( dependencies == null ) { return; } boolean failed = false; Collection<Artifact> artifacts = getProject().getArtifacts(); getLog().debug( "artifacts: " + artifacts.size() ); if ( dependencies.getIncludes() != null && !dependencies.getIncludes().isEmpty() ) { failed = checkDependencies( dependencies.getIncludes(), artifacts ); } if ( dependencies.getExcludes() != null && !dependencies.getExcludes().isEmpty() ) { failed = checkDependencies( dependencies.getExcludes(), artifacts ) || failed; } if ( failed ) { throw new MojoExecutionException( "At least one specified dependency is incorrect. Review your project configuration." ); } } /** * @param patterns list of patterns to test over artifacts * @param artifacts collection of artifacts to check * @return true if at least one of the pattern in the list matches no artifact, false otherwise */ private boolean checkDependencies( List<String> patterns, Collection<Artifact> artifacts ) { if ( dependencies == null ) { return false; } boolean failed = false; for ( String pattern : patterns ) { failed = ensurePatternMatchesAtLeastOneArtifact( pattern, artifacts ) || failed; } return failed; } /** * @param pattern pattern to test over artifacts * @param artifacts collection of artifacts to check * @return true if filter matches no artifact, false otherwise * */ private boolean ensurePatternMatchesAtLeastOneArtifact( String pattern, Collection<Artifact> artifacts ) { List<String> onePatternList = new ArrayList<>(); onePatternList.add( pattern ); ArtifactFilter filter = new IncludesArtifactFilter( onePatternList ); boolean noMatch = true; for ( Artifact artifact : artifacts ) { getLog().debug( "checking pattern: " + pattern + " against " + artifact ); if ( filter.include( artifact ) ) { noMatch = false; break; } } if ( noMatch ) { getLog().error( "pattern: " + pattern + " doesn't match any artifact." ); } return noMatch; } /** * Iterate through all the top level and transitive dependencies declared in the project and * collect all the runtime scope dependencies for inclusion in the .zip and signing. * * @throws MojoExecutionException if could not process dependencies */ private void processDependencies() throws MojoExecutionException { processDependency( getProject().getArtifact() ); AndArtifactFilter filter = new AndArtifactFilter(); // filter.add( new ScopeArtifactFilter( dependencySet.getScope() ) ); if ( dependencies != null && dependencies.getIncludes() != null && !dependencies.getIncludes().isEmpty() ) { filter.add( new IncludesArtifactFilter( dependencies.getIncludes() ) ); } if ( dependencies != null && dependencies.getExcludes() != null && !dependencies.getExcludes().isEmpty() ) { filter.add( new ExcludesArtifactFilter( dependencies.getExcludes() ) ); } Collection<Artifact> artifacts = isExcludeTransitive() ? getProject().getDependencyArtifacts() : getProject().getArtifacts(); for ( Artifact artifact : artifacts ) { if ( filter.include( artifact ) ) { processDependency( artifact ); } } } private void processDependency( Artifact artifact ) throws MojoExecutionException { // TODO: scope handler // Include runtime and compile time libraries if ( !Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) && !Artifact.SCOPE_PROVIDED.equals( artifact.getScope() ) && !Artifact.SCOPE_TEST.equals( artifact.getScope() ) ) { String type = artifact.getType(); if ( "jar".equals( type ) || "ejb-client".equals( type ) ) { boolean mainArtifact = false; if ( jnlp.isRequireMainClass() ) { // try to find if this dependency contains the main class boolean containsMainClass = getArtifactUtil().artifactContainsClass( artifact, jnlp.getMainClass() ); if ( containsMainClass ) { if ( artifactWithMainClass == null ) { mainArtifact = true; artifactWithMainClass = artifact; getLog().debug( "Found main jar. Artifact " + artifactWithMainClass + " contains the main class: " + jnlp.getMainClass() ); } else { getLog().warn( "artifact " + artifact + " also contains the main class: " + jnlp.getMainClass() + ". IGNORED." ); } } } if ( skipDependencies && !mainArtifact ) { return; } // FIXME when signed, we should update the manifest. // see http://www.mail-archive.com/[email protected]/msg08081.html // and maven1: maven-plugins/jnlp/src/main/org/apache/maven/jnlp/UpdateManifest.java // or shouldn't we? See MOJO-7 comment end of October. final File toCopy = artifact.getFile(); if ( toCopy == null ) { getLog().error( "artifact with no file: " + artifact ); getLog().error( "artifact download url: " + artifact.getDownloadUrl() ); getLog().error( "artifact repository: " + artifact.getRepository() ); getLog().error( "artifact repository: " + artifact.getVersion() ); throw new IllegalStateException( "artifact " + artifact + " has no matching file, why? Check the logs..." ); } String name = getDependencyFilenameStrategy().getDependencyFilename( artifact, outputJarVersions, isUseUniqueVersions() ); boolean copied = copyJarAsUnprocessedToDirectoryIfNecessary( toCopy, getLibDirectory(), name ); if ( copied ) { getModifiedJnlpArtifacts().add( name.substring( 0, name.lastIndexOf( '.' ) ) ); } packagedJnlpArtifacts.add( artifact ); } else // FIXME how do we deal with native libs? // we should probably identify them and package inside jars that we timestamp like the native lib // to avoid repackaging every time. What are the types of the native libs? { verboseLog( "Skipping artifact of type " + type + " for " + getLibDirectory().getName() ); } // END COPY } else { verboseLog( "Skipping artifact of scope " + artifact.getScope() + " for " + getLibDirectory().getName() ); } } private void generateJnlpFile( File outputDirectory ) throws MojoExecutionException { getLog().info("Generate the JNLP file."); // --- // get output file // --- if ( StringUtils.isBlank( jnlp.getOutputFile() ) ) { getLog().debug( "Jnlp output file name not specified. Using default output file name: launch.jnlp." ); jnlp.setOutputFile( "launch.jnlp" ); } File jnlpOutputFile = new File( outputDirectory, jnlp.getOutputFile() ); // --- // get template directory // --- File templateDirectory; if ( StringUtils.isNotBlank( jnlp.getInputTemplateResourcePath() ) ) { templateDirectory = new File( jnlp.getInputTemplateResourcePath() ); getLog().debug( "Use jnlp directory : " + templateDirectory ); } else { // use default template directory templateDirectory = getTemplateDirectory(); getLog().debug( "Use default template directory : " + templateDirectory ); } // --- // get template filename // --- if ( StringUtils.isBlank( jnlp.getInputTemplate() ) ) { getLog().debug( "Jnlp template file name not specified. Checking if default output file name exists: " + JNLP_TEMPLATE_FILENAME ); File templateFile = new File( templateDirectory, JNLP_TEMPLATE_FILENAME ); if ( templateFile.isFile() ) { jnlp.setInputTemplate( JNLP_TEMPLATE_FILENAME ); } else { getLog().debug( "Jnlp template file not found in default location. Using inbuilt one." ); } } else { File templateFile = new File( templateDirectory, jnlp.getInputTemplate() ); if ( !templateFile.isFile() ) { throw new MojoExecutionException( "The specified JNLP template does not exist: [" + templateFile + "]" ); } } String templateFileName = jnlp.getInputTemplate(); GeneratorTechnicalConfig generatorTechnicalConfig = new GeneratorTechnicalConfig( getProject(), templateDirectory, jnlp.getType().getDefaultTemplateName(), jnlpOutputFile, templateFileName, jnlp.getMainClass(), getWebstartJarURLForVelocity(), getEncoding() ); GeneratorConfig generatorConfig = new GeneratorConfig( getLibPath(), isPack200(), outputJarVersions, isUseUniqueVersions(), artifactWithMainClass, getDependencyFilenameStrategy(), packagedJnlpArtifacts, jnlpExtensions, getCodebase(), jnlp ); Generator jnlpGenerator = new Generator( getLog(), generatorTechnicalConfig, generatorConfig ); try { jnlpGenerator.generate(); } catch ( Exception e ) { getLog().debug( e.toString() ); throw new MojoExecutionException( "Could not generate the JNLP deployment descriptor", e ); } if ( addApplicationFile ) { getLog().info("Add the application file, artifactWithMainClass: " + artifactWithMainClass); // must handle outputJarVersions == true String targetFilename = getDependencyFilenameStrategy().getDependencyFilename( artifactWithMainClass, outputJarVersions, isUseUniqueVersions() ); File jarFile = new File( getLibDirectory(), targetFilename); if ( isVerbose() ) { getLog().info( "Add " + JNLP_INF_APPLICATION_JNLP + " to " + jarFile ); } JarFile inputJar = null; try { inputJar = new JarFile( jarFile ); File tempJarFile = new File( jarFile.getParentFile(), jarFile.getName() + "-temp" ); JarOutputStream jarOutputStream = new JarOutputStream( new FileOutputStream( tempJarFile ) ); try { Enumeration<JarEntry> entries = inputJar.entries(); while ( entries.hasMoreElements() ) { JarEntry jarEntry = entries.nextElement(); if (JNLP_INF_APPLICATION_JNLP.equals(jarEntry.getName())) { // skip existing JNLP-INF/APPLICATION.JNLP from jar getLog().info("Skip add existing " + JNLP_INF_APPLICATION_JNLP); continue; } jarOutputStream.putNextEntry( jarEntry ); InputStream inputStream = inputJar.getInputStream( jarEntry ); org.apache.maven.shared.utils.io.IOUtil.copy( inputStream, jarOutputStream ); } JarEntry jarEntry = new JarEntry( JNLP_INF_APPLICATION_JNLP ); jarOutputStream.putNextEntry( jarEntry ); jarOutputStream.write( FileUtils.fileRead( jnlpOutputFile ).getBytes() ); jarOutputStream.flush(); jarOutputStream.close(); } finally { org.apache.maven.shared.utils.io.IOUtil.close( jarOutputStream ); } // jarFile.delete(); signJar( tempJarFile, jarFile, false ); } catch ( IOException e ) { throw new MojoExecutionException( "Could not copy generated JNLP deployment descriptor to application file", e ); } finally { if (inputJar != null) { try { inputJar.close(); } catch (IOException e) { // ignore } } } } } private void processNativeLibs() { /* for( Iterator it = getNativeLibs().iterator(); it.hasNext(); ) { Artifact artifact = ; Artifact copiedArtifact = // similar to what we do for jars, except that we must pack them into jar instead of copying. // them File nativeLib = artifact.getFile() if(! nativeLib.endsWith( ".jar" ) ){ getLog().debug("Wrapping native library " + artifact + " into jar." ); File nativeLibJar = new File( applicationFolder, xxx + ".jar"); Jar jarTask = new Jar(); jarTask.setDestFile( nativeLib ); jarTask.setBasedir( basedir ); jarTask.setIncludes( nativeLib ); jarTask.execute(); nativeLibJar.setLastModified( nativeLib.lastModified() ); copiedArtifact = new .... } else { getLog().debug( "Copying native lib " + artifact ); copyFileToDirectory( artifact.getFile(), applicationFolder ); copiedArtifact = artifact; } copiedNativeArtifacts.add( copiedArtifact ); } } */ } private void logCollection( final String prefix, final Collection collection ) { getLog().debug( prefix + " " + collection ); if ( collection == null ) { return; } for ( Object aCollection : collection ) { getLog().debug( prefix + aCollection ); } } private void checkInput() throws MojoExecutionException { getLog().debug( "basedir " + this.basedir ); getLog().debug( "gzip " + isGzip() ); getLog().debug( "pack200 " + isPack200() ); getLog().debug( "project " + this.getProject() ); getLog().debug( "verbose " + isVerbose() ); checkJnlpConfig(); checkDependencyFilenameStrategy(); checkDependencies(); findDefaultTemplateURL( jnlp.getType() ); if ( jnlp != null && jnlp.getResources() != null ) { throw new MojoExecutionException( "The <jnlp><resources> configuration element is obsolete. Use <resourcesDirectory> instead." ); } // FIXME /* if ( !"pom".equals( getProject().getPackaging() ) ) { throw new MojoExecutionException( "'" + getProject().getPackaging() + "' packaging unsupported. Use 'pom'" ); } */ } private void checkExtension( JnlpExtension extension ) throws MojoExecutionException { if ( StringUtils.isEmpty( extension.getName() ) ) { throw new MojoExecutionException( "JnlpExtension name is mandatory. Review your project configuration." ); } if ( StringUtils.isEmpty( extension.getVendor() ) ) { throw new MojoExecutionException( "JnlpExtension vendor is mandatory. Review your project configuration." ); } if ( StringUtils.isEmpty( extension.getTitle() ) ) { throw new MojoExecutionException( "JnlpExtension name is title. Review your project configuration." ); } if ( extension.getIncludes() == null || extension.getIncludes().isEmpty() ) { throw new MojoExecutionException( "JnlpExtension need at least one include artifact. Review your project configuration." ); } } protected URL findDefaultJnlpExtensionTemplateURL() { return getClass().getClassLoader().getResource( "default-jnlp-extension-template.vm" ); } /** * Prepare extensions. * <p> * Copy all includes of all extensions as to be excluded. * * @throws MojoExecutionException if could not prepare extensions */ private void prepareExtensions() throws MojoExecutionException { List<String> includes = new ArrayList<>(); for ( JnlpExtension extension : jnlpExtensions ) { // Check extensions (mandatory name, title and vendor and at least one include) checkExtension( extension ); for ( String o : extension.getIncludes() ) { includes.add( o.trim() ); } if ( StringUtils.isEmpty( extension.getOutputFile() ) ) { String name = extension.getName() + ".jnlp"; verboseLog( "Jnlp extension output file name not specified. Using default output file name: " + name + "." ); extension.setOutputFile( name ); } } // copy all includes libs fro extensions to be exclude from the mojo // treatments (extensions by nature are already signed) if ( dependencies == null ) { dependencies = new Dependencies(); } if ( dependencies.getExcludes() == null ) { dependencies.setExcludes( new ArrayList<String>() ); } dependencies.getExcludes().addAll( includes ); } /** * Iterate through all the extensions dependencies declared in the project and * collect all the runtime scope dependencies for inclusion in the .zip and just * copy them to the lib directory. * <p> * TODO, should check that all dependencies are well signed with the same * extension with the same signer. * * @throws MojoExecutionException TODO */ private void processExtensionsDependencies() throws MojoExecutionException { Collection<Artifact> artifacts = isExcludeTransitive() ? getProject().getDependencyArtifacts() : getProject().getArtifacts(); for ( JnlpExtension extension : jnlpExtensions ) { ArtifactFilter filter = new IncludesArtifactFilter( extension.getIncludes() ); for ( Artifact artifact : artifacts ) { if ( filter.include( artifact ) ) { processExtensionDependency( extension, artifact ); } } } } private void processExtensionDependency( JnlpExtension extension, Artifact artifact ) throws MojoExecutionException { // TODO: scope handler // Include runtime and compile time libraries if ( !Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) && !Artifact.SCOPE_PROVIDED.equals( artifact.getScope() ) && !Artifact.SCOPE_TEST.equals( artifact.getScope() ) ) { String type = artifact.getType(); if ( "jar".equals( type ) || "ejb-client".equals( type ) ) { // FIXME when signed, we should update the manifest. // see http://www.mail-archive.com/[email protected]/msg08081.html // and maven1: maven-plugins/jnlp/src/main/org/apache/maven/jnlp/UpdateManifest.java // or shouldn't we? See MOJO-7 comment end of October. final File toCopy = artifact.getFile(); if ( toCopy == null ) { getLog().error( "artifact with no file: " + artifact ); getLog().error( "artifact download url: " + artifact.getDownloadUrl() ); getLog().error( "artifact repository: " + artifact.getRepository() ); getLog().error( "artifact repository: " + artifact.getVersion() ); throw new IllegalStateException( "artifact " + artifact + " has no matching file, why? Check the logs..." ); } // check jar is signed boolean jarSigned = isJarSigned( toCopy ); if ( !jarSigned ) { throw new IllegalStateException( "artifact " + artifact + " must be signed as part of an extension.." ); } String targetFilename = getDependencyFilenameStrategy().getDependencyFilename( artifact, outputJarVersions, isUseUniqueVersions() ); File targetFile = new File( getLibDirectory(), targetFilename ); boolean copied = getIoUtil().shouldCopyFile( toCopy, targetFile ); if ( copied ) { getIoUtil().copyFile( toCopy, targetFile ); verboseLog( "copy extension artifact " + toCopy ); } else { verboseLog( "already up to date artifact " + toCopy ); } // save the artifact dependency for the extension List<Artifact> deps = extensionsJnlpArtifacts.get( extension ); if ( deps == null ) { deps = new ArrayList<>(); extensionsJnlpArtifacts.put( extension, deps ); } deps.add( artifact ); } else // FIXME how do we deal with native libs? // we should probably identify them and package inside jars that we timestamp like the native lib // to avoid repackaging every time. What are the types of the native libs? { verboseLog( "Skipping artifact of type " + type + " for " + getLibDirectory().getName() ); } // END COPY } else { verboseLog( "Skipping artifact of scope " + artifact.getScope() + " for " + getLibDirectory().getName() ); } } private void generateJnlpExtensionsFile( File outputDirectory ) throws MojoExecutionException { for ( JnlpExtension jnlpExtension : jnlpExtensions ) { generateJnlpExtensionFile( outputDirectory, jnlpExtension ); } } private void generateJnlpExtensionFile( File outputDirectory, JnlpExtension extension ) throws MojoExecutionException { // --- // get output file // --- File jnlpOutputFile = new File( outputDirectory, extension.getOutputFile() ); // --- // get template directory // --- File templateDirectory; if ( StringUtils.isNotBlank( extension.getInputTemplateResourcePath() ) ) { // if user overrides the input template resource path templateDirectory = new File( extension.getInputTemplateResourcePath() ); } else { // use default template directory templateDirectory = getTemplateDirectory(); getLog().debug( "Use default jnlp directory : " + templateDirectory ); } // --- // get template filename // --- if ( StringUtils.isBlank( extension.getInputTemplate() ) ) { getLog().debug( "Jnlp extension template file name not specified. Checking if default output file name exists: " + EXTENSION_TEMPLATE_FILENAME ); File templateFile = new File( templateDirectory, EXTENSION_TEMPLATE_FILENAME ); if ( templateFile.isFile() ) { extension.setInputTemplate( EXTENSION_TEMPLATE_FILENAME ); } else { getLog().debug( "Jnlp extension template file not found in default location. Using inbuilt one." ); } } else { File templateFile = new File( templateDirectory, extension.getInputTemplate() ); if ( !templateFile.isFile() ) { throw new MojoExecutionException( "The specified JNLP extension template does not exist: [" + templateFile + "]" ); } } String templateFileName = extension.getInputTemplate(); GeneratorTechnicalConfig generatorTechnicalConfig = new GeneratorTechnicalConfig( getProject(), templateDirectory, BUILT_IN_EXTENSION_TEMPLATE_FILENAME, jnlpOutputFile, templateFileName, getJnlp().getMainClass(), getWebstartJarURLForVelocity(), getEncoding() ); ExtensionGeneratorConfig extensionGeneratorConfig = new ExtensionGeneratorConfig( getLibPath(), isPack200(), outputJarVersions, isUseUniqueVersions(), artifactWithMainClass, getDependencyFilenameStrategy(), extensionsJnlpArtifacts, getCodebase(), extension ); ExtensionGenerator jnlpGenerator = new ExtensionGenerator( getLog(), generatorTechnicalConfig, extensionGeneratorConfig ); // jnlpGenerator.setExtraConfig( new ExtensionGeneratorExtraConfig( extension, getCodebase() ) ); try { jnlpGenerator.generate(); } catch ( Exception e ) { getLog().debug( e.toString() ); throw new MojoExecutionException( "Could not generate the JNLP deployment descriptor", e ); } } }