org.codehaus.mojo.nbm.CreateWebstartAppMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nbm-maven-plugin Show documentation
Show all versions of nbm-maven-plugin Show documentation
Maven plugin for creating NetBeans modules. It defines a custom lifecycle called "nbm". During packaging, the module JAR is enhanced with NetBeans-specific manifest entries and, along with other required files, packed into a *.nbm file, ready for distribution. Additionally the plugin provides aggregator goals to create an update site or cluster for your module projects.
The newest version!
/*
* Copyright 2008 Johan Andrén.
*
* Licensed 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.
* under the License.
*/
package org.codehaus.mojo.nbm;
import static org.bitstrings.maven.nbm.utils.JarUtils.*;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarFile;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Resource;
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.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.shared.filtering.MavenResourcesExecution;
import org.apache.maven.shared.filtering.MavenResourcesFiltering;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.GenerateKey;
import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.taskdefs.Jar.FilesetManifestConfig;
import org.apache.tools.ant.taskdefs.Property;
import org.apache.tools.ant.taskdefs.SignJar;
import org.apache.tools.ant.taskdefs.Taskdef;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Parameter;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.ant.types.selectors.AndSelector;
import org.apache.tools.ant.types.selectors.FilenameSelector;
import org.apache.tools.ant.types.selectors.OrSelector;
import org.bitstrings.maven.nbm.utils.JnlpUtils;
import org.codehaus.mojo.nbm.JarsConfig.ManifestEntries;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.zip.ZipArchiver;
import org.codehaus.plexus.components.io.resources.PlexusIoResource;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.InterpolationFilterReader;
import org.netbeans.nbbuild.MakeJnlp2;
import org.netbeans.nbbuild.ModuleSelector;
import org.netbeans.nbbuild.VerifyJNLP;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.io.ByteSink;
import com.google.common.io.FileWriteMode;
import com.google.common.io.Files;
/**
* Create webstartable binaries for a 'nbm-application'.
* @author Johan Andrén
* @author Milos Kleint
* @author Pino Silvaggio
* @since 3.0
*/
//
// +p
// this crap should be refactored
//
@Mojo(name="webstart-app", defaultPhase= LifecyclePhase.PACKAGE )
public class CreateWebstartAppMojo
extends AbstractNbmMojo
{
/**
* The Maven project.
*/
@org.apache.maven.plugins.annotations.Parameter(required=true, readonly=true, property="project")
private MavenProject project;
@Component
protected MavenProjectHelper projectHelper;
/**
* The branding token for the application based on NetBeans platform.
*/
@org.apache.maven.plugins.annotations.Parameter(required=true, property="netbeans.branding.token")
protected String brandingToken;
/**
* output directory where the the NetBeans application will be created.
*/
@org.apache.maven.plugins.annotations.Parameter(required=true, defaultValue="${project.build.directory}")
private File outputDirectory;
/**
* Ready-to-deploy WAR containing application in JNLP packaging.
*
*/
@org.apache.maven.plugins.annotations.Parameter(required=true, defaultValue="${project.build.directory}/${project.artifactId}-${project.version}-jnlp.war")
private File destinationFile;
/**
* Artifact Classifier to use for the webstart distributable zip file.
* @since 3.1
*/
@org.apache.maven.plugins.annotations.Parameter(defaultValue="webstart", property="nbm.webstart.classifier")
private String webstartClassifier;
/**
* Codebase value within *.jnlp files.
* Defining this parameter is generally a bad idea.
*/
@org.apache.maven.plugins.annotations.Parameter(property="nbm.webstart.codebase")
private String codebase;
/**
* A custom master JNLP file. If not defined, the
* default one is used.
* The following expressions can be used within the file and will
* be replaced when generating content.
*
* - ${jnlp.resources}
* - ${jnlp.codebase} - the 'codebase' parameter value is passed in.
* - ${app.name}
* - ${app.title}
* - ${app.vendor}
* - ${app.description}
* - ${branding.token} - the 'brandingToken' parameter value is passed in.
* - ${netbeans.jnlp.fixPolicy}
*
*/
@org.apache.maven.plugins.annotations.Parameter
private File masterJnlpFile;
/**
* The basename (minus .jnlp extension) of the master JNLP file in the output.
* This file will be the entry point for javaws.
* Defaults to the branding token.
* @since 3.5
*/
@org.apache.maven.plugins.annotations.Parameter(property="master.jnlp.file.name")
private String masterJnlpFileName;
/**
* keystore location for signing the nbm file
*/
@org.apache.maven.plugins.annotations.Parameter(property="keystore")
private String keystore;
/**
* keystore password
*/
@org.apache.maven.plugins.annotations.Parameter(property="keystorepass")
private String keystorepassword;
/**
* keystore alias
*/
@org.apache.maven.plugins.annotations.Parameter(property="keystorealias")
private String keystorealias;
/**
* keystore type
* @since 3.5
*/
@org.apache.maven.plugins.annotations.Parameter(property="keystoretype")
private String keystoretype;
/**
* If set true, build-jnlp target creates versioning info in jnlp descriptors and version.xml files.
* This allows for incremental updates of Webstart applications, but requires download via
* JnlpDownloadServlet
* Defaults to false, which means versioning
* info is not generated (see
* http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/downloadservletguide.html#resources).
*
*/
@org.apache.maven.plugins.annotations.Parameter(defaultValue="false", property="nbm.webstart.versions")
private boolean processJarVersions;
// +p
@org.apache.maven.plugins.annotations.Parameter( defaultValue="false", property="nbm.webstart.signWar" )
private boolean signWar;
// +p
@org.apache.maven.plugins.annotations.Parameter(
defaultValue="false", property="nbm.webstart.generateJnlpApplicationTemplate" )
private boolean generateJnlpApplicationTemplate;
/**
* additional command line arguments. Eg.
* -J-Xdebug -J-Xnoagent -J-Xrunjdwp:transport=dt_socket,suspend=n,server=n,address=8888
* can be used to debug the IDE.
*/
// +p
@org.apache.maven.plugins.annotations.Parameter( property="netbeans.run.params" )
private String additionalArguments;
// +p
@org.apache.maven.plugins.annotations.Parameter( property="nbm.signing.threads", defaultValue="0" )
private int signingThreads;
// +p
@org.apache.maven.plugins.annotations.Parameter( property="nbm.signing.maximumthreads", defaultValue="0" )
private int signingMaximumThreads;
// +p
@org.apache.maven.plugins.annotations.Parameter( property="nbm.signing.force", defaultValue="true" )
private boolean signingForce;
// +p
@org.apache.maven.plugins.annotations.Parameter( property="nbm.signing.tsacert" )
private String signingTsaCert;
// +p
@org.apache.maven.plugins.annotations.Parameter( property="nbm.signing.tsaurl" )
private String signingTsaUrl;
// +p
@org.apache.maven.plugins.annotations.Parameter(
property="nbm.signing.removeExistingSignatures",
defaultValue="false")
private boolean signingRemoveExistingSignatures;
// +p
@org.apache.maven.plugins.annotations.Parameter( property="nbm.signing.maxMemory" )
private String signingMaxMemory = "96m";
// +p
@org.apache.maven.plugins.annotations.Parameter(
property="nbm.signing.retryCount",
defaultValue="5")
private int signingRetryCount;
@org.apache.maven.plugins.annotations.Parameter(
property="encoding", defaultValue="${project.build.sourceEncoding}" )
private String encoding;
@org.apache.maven.plugins.annotations.Parameter( property="session", readonly=true, required=true )
private MavenSession session;
// +p
@Component
private MavenResourcesFiltering mavenResourcesFiltering;
// +p
@org.apache.maven.plugins.annotations.Parameter( defaultValue="true" )
private boolean autoManifestSecurityEntries = true;
// +p
@org.apache.maven.plugins.annotations.Parameter
private List jarsConfigs;
// +p
@org.apache.maven.plugins.annotations.Parameter
private List webappResources;
// +p
@org.apache.maven.plugins.annotations.Parameter
private String applicationName;
// +p
@org.apache.maven.plugins.annotations.Parameter( defaultValue="false" )
private boolean pack200 = false;
// +p
@org.apache.maven.plugins.annotations.Parameter
private Integer pack200Effort = null;
// +p
@org.apache.maven.plugins.annotations.Parameter( defaultValue="false" )
private boolean generateJnlpTimestamp;
// +p
@org.apache.maven.plugins.annotations.Parameter( defaultValue="true" )
private boolean verifyJnlp = true;
@org.apache.maven.plugins.annotations.Parameter( defaultValue="true" )
private boolean validateJnlpDtd = true;
@org.apache.maven.plugins.annotations.Parameter( defaultValue="*" )
private String includeLocales;
// +p
private String jarPermissions;
private String jarCodebase;
private String jnlpSecurity;
// +p
@org.apache.maven.plugins.annotations.Parameter( defaultValue="false" )
private boolean optimize;
@Component
protected ArchiverManager archiverManager;
/**
*
* @throws org.apache.maven.plugin.MojoExecutionException
* @throws org.apache.maven.plugin.MojoFailureException
*/
@Override
public void execute()
throws MojoExecutionException, MojoFailureException
{
if ( "none".equalsIgnoreCase( includeLocales ) )
{
includeLocales = "";
}
if ( signingThreads < 1 )
{
signingThreads = Runtime.getRuntime().availableProcessors();
}
if ( ( signingMaximumThreads > 0 ) && ( signingThreads > signingMaximumThreads ) )
{
signingThreads = signingMaximumThreads;
}
getLog().info( "Using " + signingThreads + " signing threads." );
if ( !"nbm-application".equals( project.getPackaging() ) )
{
throw new MojoExecutionException(
"This goal only makes sense on project with nbm-application packaging." );
}
final Project antProject = antProject();
getLog().warn( "WARNING: Unsigned and self-signed WebStart applications are deprecated from JDK7u21 onwards. To ensure future correct functionality please use trusted certificate.");
if ( keystore != null && keystorealias != null && keystorepassword != null )
{
File ks = new File( keystore );
if ( !ks.exists() )
{
throw new MojoFailureException( "Cannot find keystore file at " + ks.getAbsolutePath() );
}
else
{
//proceed..
}
}
else if ( keystore != null || keystorepassword != null || keystorealias != null )
{
throw new MojoFailureException(
"If you want to sign the jnlp application, you need to define all three keystore related parameters." );
}
else
{
File generatedKeystore = new File( outputDirectory, "generated.keystore" );
if ( ! generatedKeystore.exists() )
{
getLog().warn( "Keystore related parameters not set, generating a default keystore." );
GenerateKey genTask = (GenerateKey) antProject.createTask( "genkey" );
genTask.setAlias( "jnlp" );
genTask.setStorepass( "netbeans" );
genTask.setDname( "CN=" + System.getProperty( "user.name" ) );
genTask.setKeystore( generatedKeystore.getAbsolutePath() );
genTask.execute();
}
keystore = generatedKeystore.getAbsolutePath();
keystorepassword = "netbeans";
keystorealias = "jnlp";
}
Taskdef taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( MakeJnlp2.class.getName() );
taskdef.setName( "makejnlp" );
taskdef.execute();
taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( Jar.class.getName() );
taskdef.setName( "jar" );
taskdef.execute();
taskdef = (Taskdef) antProject.createTask( "taskdef" );
taskdef.setClassname( VerifyJNLP.class.getName() );
taskdef.setName( "verifyjnlp" );
taskdef.execute();
// +p
try
{
final File webstartBuildDir =
new File( outputDirectory + File.separator + "webstart" + File.separator + brandingToken );
if ( webstartBuildDir.exists() )
{
FileUtils.deleteDirectory( webstartBuildDir );
}
webstartBuildDir.mkdirs();
// P: copy webappResources --[
MavenResourcesExecution mavenResourcesExecution =
new MavenResourcesExecution(
webappResources,
webstartBuildDir,
project, encoding,
Collections.EMPTY_LIST, Collections.EMPTY_LIST,
session );
mavenResourcesExecution.setEscapeWindowsPaths( true );
mavenResourcesFiltering.filterResources( mavenResourcesExecution );
// ]--
final String localCodebase = codebase != null ? codebase : webstartBuildDir.toURI().toString();
getLog().info( "Generating webstartable binaries at " + webstartBuildDir.getAbsolutePath() );
final File nbmBuildDirFile = new File( outputDirectory, brandingToken );
// +p (needs to be before make jnlp)
//TODO is it really netbeans/
if ( masterJnlpFileName == null )
{
masterJnlpFileName = brandingToken;
}
Properties props = new Properties();
props.setProperty( "jnlp.codebase", localCodebase );
props.setProperty( "app.name", brandingToken );
props.setProperty( "app.title", project.getName() );
if ( project.getOrganization() != null )
{
props.setProperty( "app.vendor", project.getOrganization().getName() );
}
else
{
props.setProperty( "app.vendor", "Nobody" );
}
String description = project.getDescription() != null ? project.getDescription() : "No Project Description";
props.setProperty( "app.description", description );
props.setProperty( "branding.token", brandingToken );
props.setProperty( "master.jnlp.file.name", masterJnlpFileName );
props.setProperty( "netbeans.jnlp.fixPolicy", "false" );
StringBuilder stBuilder = new StringBuilder();
if ( additionalArguments != null )
{
StringTokenizer st = new StringTokenizer( additionalArguments );
while ( st.hasMoreTokens() )
{
String arg = st.nextToken();
if ( arg.startsWith( "-J" ) )
{
if ( stBuilder.length() > 0 )
{
stBuilder.append( ' ' );
}
stBuilder.append( arg.substring( 2 ) );
}
}
}
props.setProperty( "netbeans.run.params", stBuilder.toString() );
final File masterJnlp = new File( webstartBuildDir, masterJnlpFileName + ".jnlp" );
filterCopy( masterJnlpFile, "master.jnlp", masterJnlp, props );
if ( generateJnlpTimestamp ) // \/\/\/\/ bad bad bad \/\/\/\/
{
final File masterJnlpFileTmp = File.createTempFile( masterJnlpFileName + "_", "" );
Files.append(
JnlpUtils.getCurrentJnlpTimestamp() + "\n",
masterJnlpFileTmp,
Charset.forName( "UTF-8" ) );
ByteSink sink = Files.asByteSink( masterJnlpFileTmp, FileWriteMode.APPEND );
sink.write( Files.toByteArray(masterJnlp) );
Files.copy( masterJnlpFileTmp, masterJnlp );
}
File startup = copyLauncher( outputDirectory, nbmBuildDirFile );
String masterJnlpStr = FileUtils.fileRead( masterJnlp );
// P: JNLP-INF/APPLICATION_TEMPLATE.JNLP support --[
// this can be done better and will
// ashamed
if ( generateJnlpApplicationTemplate )
{
File jnlpInfDir = new File( outputDirectory, "JNLP-INF" );
getLog().info( "Generate JNLP application template under: " + jnlpInfDir );
jnlpInfDir.mkdirs();
File jnlpTemplate = new File( jnlpInfDir, "APPLICATION_TEMPLATE.JNLP" );
masterJnlpStr = masterJnlpStr
.replaceAll( "( ";
}
startupManifestEntries.setPermissions( jarPermissions );
if ( applicationName == null )
{
String jnlpApplicationTitle =
(String) xpath.evaluate( "/jnlp/information/title", doc, XPathConstants.STRING );
applicationName =
jnlpApplicationTitle == null
? brandingToken
: jnlpApplicationTitle;
}
startupManifestEntries.setApplicationName( applicationName );
// +p
if ( autoManifestSecurityEntries )
{
if ( jarsConfigs == null )
{
jarsConfigs = new ArrayList();
}
jarsConfigs.add( 0, startupConfig );
}
final List signJarJarsConfigs = buildSignJarJarsConfigs( jarsConfigs );
File jnlpDestination = new File(
webstartBuildDir.getAbsolutePath() + File.separator + "startup.jar" );
SignJar signTask = (SignJar) antProject.createTask( "signjar" );
signTask.setKeystore( keystore );
signTask.setStorepass( keystorepassword );
signTask.setAlias( keystorealias );
if ( keystoretype != null )
{
signTask.setStoretype( keystoretype );
}
signTask.setForce( signingForce );
signTask.setTsacert( signingTsaCert );
signTask.setTsaurl( signingTsaUrl );
signTask.setMaxmemory( signingMaxMemory );
signTask.setRetryCount( signingRetryCount );
signTask.setUnsignFirst( signingRemoveExistingSignatures );
signTask.setJarsConfigs( buildSignJarJarsConfigs( Collections.singletonList( startupConfig ) ) );
signTask.setBasedir( nbmBuildDirFile );
signTask.setSignedjar( jnlpDestination );
signTask.setJar( startup );
signTask.setPack200( pack200 );
signTask.setPack200Effort( pack200Effort );
signTask.execute();
// <-- all of this will be refactored soon ]--
// FileUtils.copyDirectoryStructureIfModified( nbmBuildDirFile, webstartBuildDir );
MakeJnlp2 jnlpTask = (MakeJnlp2) antProject.createTask( "makejnlp" );
jnlpTask.setOptimize(optimize);
jnlpTask.setIncludelocales(includeLocales);
jnlpTask.setDir( webstartBuildDir );
jnlpTask.setCodebase( localCodebase );
//TODO, how to figure verify excludes..
jnlpTask.setVerify( false );
jnlpTask.setPermissions( jnlpSecurity );
jnlpTask.setSignJars( true );
jnlpTask.setAlias( keystorealias );
jnlpTask.setKeystore( keystore );
jnlpTask.setStorePass( keystorepassword );
if ( keystoretype != null )
{
jnlpTask.setStoreType( keystoretype );
}
jnlpTask.setSigningForce( signingForce );
jnlpTask.setSigningTsaCert( signingTsaCert );
jnlpTask.setSigningTsaUrl( signingTsaUrl );
jnlpTask.setUnsignFirst( signingRemoveExistingSignatures );
jnlpTask.setJarsConfigs( signJarJarsConfigs );
jnlpTask.setSigningMaxMemory( signingMaxMemory );
jnlpTask.setSigningRetryCount( signingRetryCount );
jnlpTask.setBasedir( nbmBuildDirFile );
jnlpTask.setNbThreads( signingThreads );
jnlpTask.setProcessJarVersions( processJarVersions );
jnlpTask.setPack200( pack200 );
jnlpTask.setPack200Effort( pack200Effort );
FileSet fs = jnlpTask.createModules();
fs.setDir( nbmBuildDirFile );
OrSelector or = new OrSelector();
AndSelector and = new AndSelector();
FilenameSelector inc = new FilenameSelector();
inc.setName( "*/modules/**/*.jar" );
or.addFilename( inc );
inc = new FilenameSelector();
inc.setName( "*/lib/**/*.jar" );
or.addFilename( inc );
inc = new FilenameSelector();
inc.setName( "*/core/**/*.jar" );
or.addFilename( inc );
ModuleSelector ms = new ModuleSelector();
Parameter included = new Parameter();
included.setName( "includeClusters" );
included.setValue( "" );
Parameter excluded = new Parameter();
excluded.setName( "excludeClusters" );
excluded.setValue( "" );
Parameter exModules = new Parameter();
exModules.setName( "excludeModules" );
exModules.setValue( "" );
ms.setParameters( new Parameter[]
{
included,
excluded,
exModules
} );
and.add( or );
and.add( ms );
fs.addAnd( and );
jnlpTask.execute();
Set locales = jnlpTask.getExecutedLocales();
String extSnippet = generateExtensions( fs, antProject, "" ); // "netbeans/"
//branding
DirectoryScanner ds = new DirectoryScanner();
ds.setBasedir( nbmBuildDirFile );
final List localeIncludes = new ArrayList();
final List localeExcludes = new ArrayList();
localeIncludes.add( "**/locale/*.jar" );
if ( includeLocales != null )
{
List excludes =
Lists.newArrayList(
Splitter.on(',').trimResults().omitEmptyStrings().split(includeLocales)
);
for ( String exclude : (Collection) CollectionUtils.subtract( locales, excludes ) )
{
localeExcludes.add( "**/locale/*_" + exclude + ".jar" );
}
}
ds.setIncludes( localeIncludes.toArray( new String[localeIncludes.size()] ) );
ds.setExcludes( localeExcludes.toArray( new String[localeExcludes.size()] ) );
ds.scan();
String[] includes = ds.getIncludedFiles();
StringBuilder brandRefs =
new StringBuilder(
" \n" );
if ( includes != null && includes.length > 0 )
{
final File brandingDir = new File( webstartBuildDir, "branding" );
brandingDir.mkdirs();
for ( String incBran : includes )
{
File source = new File( nbmBuildDirFile, incBran );
File dest = new File( brandingDir, source.getName() );
brandRefs.append( " \n" );
}
final ExecutorService executorService = Executors.newFixedThreadPool( signingThreads );
final List threadException = new ArrayList();
for (final String toSign : includes)
{
executorService.execute( new Runnable()
{
@Override
public void run()
{
try
{
File toSignFile = new File( nbmBuildDirFile, toSign );
SignJar signTask = (SignJar) antProject.createTask( "signjar" );
if ( keystoretype != null )
{
signTask.setStoretype( keystoretype );
}
signTask.setKeystore( keystore );
signTask.setStorepass( keystorepassword );
signTask.setAlias( keystorealias );
signTask.setForce( signingForce );
signTask.setTsacert( signingTsaCert );
signTask.setTsaurl( signingTsaUrl );
signTask.setMaxmemory( signingMaxMemory );
signTask.setRetryCount( signingRetryCount );
signTask.setUnsignFirst( signingRemoveExistingSignatures );
signTask.setJarsConfigs( signJarJarsConfigs );
signTask.setJar( toSignFile );
signTask.setDestDir( brandingDir );
signTask.setBasedir( nbmBuildDirFile );
signTask.setDestFlatten( true );
signTask.setPack200( pack200 );
signTask.setPack200Effort( pack200Effort );
signTask.execute();
}
catch ( Exception e )
{
threadException.add( e );
}
}
} );
}
executorService.shutdown();
executorService.awaitTermination( Long.MAX_VALUE, TimeUnit.NANOSECONDS );
if ( !threadException.isEmpty() )
{
throw threadException.get( 0 );
}
}
File modulesJnlp = new File(
webstartBuildDir.getAbsolutePath() + File.separator + "modules.jnlp" );
props.setProperty( "jnlp.branding.jars", brandRefs.toString() );
props.setProperty( "jnlp.resources", extSnippet );
filterCopy( null, /* filename is historical */"branding.jnlp", modulesJnlp, props );
if ( verifyJnlp )
{
getLog().info( "Verifying generated webstartable content." );
VerifyJNLP verifyTask = ( VerifyJNLP ) antProject.createTask( "verifyjnlp" );
FileSet verify = new FileSet();
verify.setFile( masterJnlp );
verifyTask.addConfiguredFileset( verify );
verifyTask.execute();
}
// create zip archive
if ( destinationFile.exists() )
{
destinationFile.delete();
}
ZipArchiver archiver = new ZipArchiver();
if ( codebase != null )
{
getLog().warn( "Defining /${nbm.webstart.codebase} is generally unnecessary" );
archiver.addDirectory( webstartBuildDir );
}
else
{
archiver.addDirectory( webstartBuildDir, null, new String[] { "**/*.jnlp" } );
for ( final File jnlp : webstartBuildDir.listFiles() )
{
if ( !jnlp.getName().endsWith( ".jnlp" ) )
{
continue;
}
archiver.addResource( new PlexusIoResource() {
public @Override InputStream getContents() throws IOException
{
return new ByteArrayInputStream( FileUtils.fileRead( jnlp, "UTF-8" ).replace( localCodebase, "$$codebase" ).getBytes( "UTF-8" ) );
}
public @Override long getLastModified()
{
return jnlp.lastModified();
}
public @Override boolean isExisting()
{
return true;
}
public @Override long getSize()
{
return UNKNOWN_RESOURCE_SIZE;
}
public @Override URL getURL() throws IOException
{
return null;
}
public @Override String getName()
{
return jnlp.getAbsolutePath();
}
public @Override boolean isFile()
{
return true;
}
public @Override boolean isDirectory()
{
return false;
}
@Override
public boolean isSymbolicLink()
{
return false;
}
}, jnlp.getName(), archiver.getDefaultFileMode() );
}
}
File jdkhome = new File( System.getProperty( "java.home" ) );
File servlet = new File( jdkhome, "sample/jnlp/servlet/jnlp-servlet.jar" );
if ( ! servlet.exists() )
{
servlet = new File( jdkhome.getParentFile(), "sample/jnlp/servlet/jnlp-servlet.jar" );
if ( !servlet.exists() )
{
servlet = File.createTempFile( "nbm_", "jnlp-servlet.jar" );
FileUtils.copyURLToFile(
Thread.currentThread().getContextClassLoader()
.getResource( "jnlp-servlet.jar" ),
servlet );
}
}
if ( servlet.exists() )
{
File servletDir = new File( webstartBuildDir, "WEB-INF/lib" );
servletDir.mkdirs();
signTask = (SignJar) antProject.createTask( "signjar" );
signTask.setKeystore( keystore );
signTask.setStorepass( keystorepassword );
signTask.setAlias( keystorealias );
signTask.setForce( signingForce );
signTask.setTsacert( signingTsaCert );
signTask.setTsaurl( signingTsaUrl );
signTask.setMaxmemory( signingMaxMemory );
signTask.setRetryCount( signingRetryCount );
signTask.setJar( servlet );
signTask.setSignedjar( new File( servletDir, "jnlp-servlet.jar" ) );
signTask.execute();
//archiver.addFile( servlet, "WEB-INF/lib/jnlp-servlet.jar" );
archiver.addResource( new PlexusIoResource() {
public @Override InputStream getContents() throws IOException
{
return new ByteArrayInputStream( ( "" +
"\n" +
" \n" +
" JnlpDownloadServlet \n" +
" jnlp.sample.servlet.JnlpDownloadServlet \n" +
" \n" +
" \n" +
" JnlpDownloadServlet \n" +
" *.jnlp \n" +
" \n" +
" \n" +
" JnlpDownloadServlet \n" +
" *.jar \n" +
" \n" +
" \n" +
" jnlp \n" +
" application/x-java-jnlp-file \n" +
" \n" +
" \n" ).getBytes() );
}
public @Override long getLastModified()
{
return UNKNOWN_MODIFICATION_DATE;
}
public @Override boolean isExisting()
{
return true;
}
public @Override long getSize()
{
return UNKNOWN_RESOURCE_SIZE;
}
public @Override URL getURL() throws IOException
{
return null;
}
public @Override String getName()
{
return "web.xml";
}
public @Override boolean isFile()
{
return true;
}
public @Override boolean isDirectory()
{
return false;
}
@Override
public boolean isSymbolicLink()
{
return false;
}
}, "WEB-INF/web.xml", archiver.getDefaultFileMode() );
}
archiver.setDestFile( destinationFile );
archiver.createArchive();
if (signWar)
{
signTask = (SignJar) antProject.createTask( "signjar" );
signTask.setKeystore( keystore );
signTask.setStorepass( keystorepassword );
signTask.setAlias( keystorealias );
signTask.setForce( signingForce );
signTask.setTsacert( signingTsaCert );
signTask.setTsaurl( signingTsaUrl );
signTask.setMaxmemory( signingMaxMemory );
signTask.setRetryCount( signingRetryCount );
signTask.setJar( destinationFile );
signTask.execute();
}
// attach standalone so that it gets installed/deployed
projectHelper.attachArtifact( project, "war", webstartClassifier, destinationFile );
}
catch ( Exception ex )
{
throw new MojoExecutionException( "Error creating webstartable binary.", ex );
}
}
/**
* @param standaloneBuildDir
* @return The name of the jnlp-launcher jarfile in the build directory
*/
private File copyLauncher( File standaloneBuildDir, File builtInstallation )
throws IOException
{
File jnlpStarter =
new File( builtInstallation.getAbsolutePath() + File.separator + "harness" + File.separator + "jnlp"
+ File.separator + "jnlp-launcher.jar" );
// buffer so it isn't reading a byte at a time!
InputStream source = null;
FileOutputStream outstream = null;
try
{
if ( !jnlpStarter.exists() )
{
source = getClass().getClassLoader().getResourceAsStream(
"harness/jnlp/jnlp-launcher.jar" );
}
else
{
source = new FileInputStream( jnlpStarter );
}
File jnlpDestination = new File(
standaloneBuildDir.getAbsolutePath() + File.separator + "jnlp-launcher.jar" );
outstream = new FileOutputStream( jnlpDestination );
IOUtil.copy( source, outstream );
return jnlpDestination;
}
finally
{
IOUtil.close( source );
IOUtil.close( outstream );
}
}
private void filterCopy( File sourceFile, String resourcePath, File destinationFile, Properties filterProperties )
throws IOException
{
// buffer so it isn't reading a byte at a time!
Reader source = null;
Writer destination = null;
try
{
InputStream instream;
if ( sourceFile != null )
{
instream = new FileInputStream( sourceFile );
}
else
{
instream = getClass().getClassLoader().getResourceAsStream( resourcePath );
}
FileOutputStream outstream = new FileOutputStream( destinationFile );
source = new BufferedReader( new InputStreamReader( instream, "UTF-8" ) );
destination = new OutputStreamWriter( outstream, "UTF-8" );
// support ${token}
Reader reader = new InterpolationFilterReader( source, filterProperties, "${", "}" );
IOUtil.copy( reader, destination );
}
finally
{
IOUtil.close( source );
IOUtil.close( destination );
}
}
/**
* copied from MakeMasterJNLP ant task.
* @param files
* @param antProject
* @param masterPrefix
* @return
* @throws java.io.IOException
*/
private String generateExtensions( FileSet files, Project antProject, String masterPrefix )
throws IOException
{
StringBuilder buff = new StringBuilder();
for ( String nm : files.getDirectoryScanner( antProject ).getIncludedFiles() )
{
File jar = new File( files.getDir( antProject ), nm );
if ( !jar.canRead() )
{
throw new IOException( "Cannot read file: " + jar );
}
try ( JarFile theJar = new JarFile( jar ) )
{
Attributes attr = theJar.getManifest().getMainAttributes();
String codenamebase = attr.getValue( "OpenIDE-Module" );
if ( codenamebase == null )
{
codenamebase = attr.getValue("Bundle-SymbolicName");
}
if ( codenamebase == null )
{
throw new IOException( "Not a NetBeans Module: " + jar );
}
// see http://hg.netbeans.org/main-silver/rev/87823abb86d9
if (codenamebase.equals("org.objectweb.asm.all")
&& jar.getParentFile().getName().equals("core")
&& jar.getParentFile().getParentFile().getName().startsWith("platform"))
{
continue;
}
{
int slash = codenamebase.indexOf( '/' );
if ( slash >= 0 )
{
codenamebase = codenamebase.substring( 0, slash );
}
}
String dashcnb = codenamebase.replace( '.', '-' );
buff.append( " \n" );
}
}
return buff.toString();
}
private List buildSignJarJarsConfigs( List jarsConfigs )
{
List signJarJarsConfigs = new ArrayList();
if ( jarsConfigs != null )
{
for ( JarsConfig jarsConfig : jarsConfigs )
{
SignJar.JarsConfig signJarJarsConfig = new SignJar.JarsConfig();
if ( jarsConfig.getJarSet() != null )
{
signJarJarsConfig.setIncludes( Joiner.on(',').join( jarsConfig.getJarSet().getIncludes() ) );
signJarJarsConfig.setExcludes( Joiner.on(',').join( jarsConfig.getJarSet().getExcludes() ) );
}
signJarJarsConfig.setUnsignFirst( jarsConfig.getRemoveExistingSignatures() );
List signJarManifestAttributes = new ArrayList();
JarsConfig.ManifestEntries manifestEntries = jarsConfig.getManifestEntries();
if ( manifestEntries != null )
{
if ( manifestEntries.getTrustedOnly() != null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_TRUSTED_ONLY,
manifestEntries.getTrustedOnly().toString() ) );
}
if ( manifestEntries.getTrustedLibrary() != null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_TRUSTED_LIBRARY,
manifestEntries.getTrustedLibrary().toString() ) );
}
if ( manifestEntries.getPermissions() != null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_PERMISSIONS,
manifestEntries.getPermissions() ) );
}
if ( manifestEntries.getCodebase() != null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_CODEBASE,
manifestEntries.getCodebase() ) );
}
if ( manifestEntries.getApplicationName() != null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_APPLICATION_NAME,
manifestEntries.getApplicationName() ) );
}
if ( manifestEntries.getApplicationLibraryAllowableCodebase() != null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_APPLICATION_LIBRARY_ALLOWABLE_CODEBASE,
manifestEntries.getApplicationLibraryAllowableCodebase() ) );
}
if ( manifestEntries.getCallerAllowableCodebase() != null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_CALLER_ALLOWABLE_CODEBASE,
manifestEntries.getCallerAllowableCodebase() ) );
}
Map jarsConfigManifestAttributes = manifestEntries.getExtraAttributes();
if ( jarsConfigManifestAttributes != null )
{
for ( Map.Entry entry : jarsConfigManifestAttributes.entrySet() )
{
signJarManifestAttributes.add(
createAntProperty( entry.getKey(), entry.getValue() ) );
}
}
List jarsConfigRemoveAttributes = manifestEntries.getRemoveAttributes();
if ( jarsConfigRemoveAttributes == null )
{
manifestEntries.setRemoveAttributes( jarsConfigRemoveAttributes = new ArrayList() );
}
if ( ( manifestEntries.getRemoveClassPath() == null )
|| manifestEntries.getRemoveClassPath().equals( true ) )
{
jarsConfigRemoveAttributes.add( MANIFEST_ATTR_CLASS_PATH );
}
signJarJarsConfig.setRemoveAttributes(jarsConfigRemoveAttributes);
}
if ( autoManifestSecurityEntries )
{
if ( manifestEntries == null )
{
manifestEntries = new ManifestEntries();
}
if ( manifestEntries.getPermissions() == null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_PERMISSIONS,
jarPermissions ) );
}
if ( manifestEntries.getCodebase() == null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_CODEBASE,
jarCodebase ) );
}
if ( manifestEntries.getApplicationName() == null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_APPLICATION_NAME,
applicationName ) );
}
if ( manifestEntries.getTrustedLibrary() == null )
{
signJarManifestAttributes
.add(
createAntProperty(
MANIFEST_ATTR_TRUSTED_LIBRARY,
"true" ) );
}
}
signJarJarsConfig.setExtraManifestAttributes( signJarManifestAttributes );
signJarJarsConfigs.add( signJarJarsConfig );
}
}
return signJarJarsConfigs;
}
private Property createAntProperty( String name, String value )
{
Property property = new Property();
property.setProject( antProject() );
property.setName( name );
property.setValue( value );
property.execute();
return property;
}
}