Java tutorial
/* * Copyright 2008 Johan Andrn. * * 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.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.io.ByteSink; import com.google.common.io.FileWriteMode; import com.google.common.io.Files; /** * Create webstartable binaries for a 'nbm-application'. * @author <a href="mailto:johan.andren@databyran.se">Johan Andrn</a> * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a> * @author <a href="bitstrings.org">Pino Silvaggio</a> * @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. * <strong>Defining this parameter is generally a bad idea.</strong> */ @org.apache.maven.plugins.annotations.Parameter(property = "nbm.webstart.codebase") private String codebase; /** * A custom master JNLP file. If not defined, the * <a href="http://mojo.codehaus.org/nbm-maven-plugin/masterjnlp.txt">default one</a> is used. * The following expressions can be used within the file and will * be replaced when generating content. * <ul> * <li>${jnlp.resources}</li> * <li>${jnlp.codebase} - the 'codebase' parameter value is passed in.</li> * <li>${app.name}</li> * <li>${app.title}</li> * <li>${app.vendor}</li> * <li>${app.description}</li> * <li>${branding.token} - the 'brandingToken' parameter value is passed in.</li> * <li>${netbeans.jnlp.fixPolicy}</li> * </ul> */ @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<JarsConfig> jarsConfigs; // +p @org.apache.maven.plugins.annotations.Parameter private List<Resource> 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("(<jnlp.*codebase\\ *=\\ *)\"((?!\").)*", "$1\"*") .replaceAll("(<jnlp.*href\\ *=\\ *)\"((?!\").)*", "$1\"*"); FileUtils.fileWrite(jnlpTemplate, masterJnlpStr); File startupMerged = new File(outputDirectory, "startup-jnlpinf.jar"); Jar jar = (Jar) antProject.createTask("jar"); jar.setDestFile(startupMerged); jar.setFilesetmanifest((FilesetManifestConfig) EnumeratedAttribute .getInstance(FilesetManifestConfig.class, "merge")); FileSet jnlpInfDirectoryFileSet = new FileSet(); jnlpInfDirectoryFileSet.setDir(outputDirectory); jnlpInfDirectoryFileSet.setIncludes("JNLP-INF/**"); jar.addFileset(jnlpInfDirectoryFileSet); ZipFileSet startupJar = new ZipFileSet(); startupJar.setSrc(startup); jar.addZipfileset(startupJar); jar.execute(); startup = startupMerged; getLog().info("APPLICATION_TEMPLATE.JNLP generated - startup.jar: " + startup); } final JarsConfig startupConfig = new JarsConfig(); ManifestEntries startupManifestEntries = new ManifestEntries(); startupConfig.setManifestEntries(startupManifestEntries); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); if (!validateJnlpDtd) { factory.setValidating(false); factory.setNamespaceAware(true); factory.setFeature("http://xml.org/sax/features/namespaces", false); factory.setFeature("http://xml.org/sax/features/validation", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); } DocumentBuilder builder = factory.newDocumentBuilder(); final BufferedReader masterJnlpStrReader = new BufferedReader(new StringReader(masterJnlpStr)); if (generateJnlpTimestamp) { masterJnlpStrReader.readLine(); } Document doc = builder.parse(new InputSource(masterJnlpStrReader)); Element jnlpRoot = doc.getDocumentElement(); jarCodebase = jnlpRoot.getAttribute("codebase"); if (jarCodebase.isEmpty()) { jarCodebase = "*"; } startupManifestEntries.setCodebase(jarCodebase); XPath xpath = XPathFactory.newInstance().newXPath(); Node jnlpSecurityPermission = (Node) xpath.evaluate( "(/jnlp/security/all-permissions | /jnlp/security/j2ee-application-client-permissions)[1]", doc, XPathConstants.NODE); if (jnlpSecurityPermission == null) { jarPermissions = "sandbox"; jnlpSecurity = ""; } else { jarPermissions = "all-permissions"; jnlpSecurity = "<security><" + jnlpSecurityPermission.getNodeName() + "/></security>"; } 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<JarsConfig>(); } jarsConfigs.add(0, startupConfig); } final List<SignJar.JarsConfig> 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<String> locales = jnlpTask.getExecutedLocales(); String extSnippet = generateExtensions(fs, antProject, ""); // "netbeans/" //branding DirectoryScanner ds = new DirectoryScanner(); ds.setBasedir(nbmBuildDirFile); final List<String> localeIncludes = new ArrayList<String>(); final List<String> localeExcludes = new ArrayList<String>(); localeIncludes.add("**/locale/*.jar"); if (includeLocales != null) { List<String> excludes = Splitter.on(',').trimResults().omitEmptyStrings() .splitToList(includeLocales); for (String exclude : (Collection<String>) 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( "<property name=\"jnlp.packEnabled\" value=\"" + String.valueOf(pack200) + "\"/>\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(" <jar href=\'branding/").append(dest.getName()).append("\'/>\n"); } final ExecutorService executorService = Executors.newFixedThreadPool(signingThreads); final List<Exception> threadException = new ArrayList<Exception>(); 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 <codebase>/${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; } }, 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(("" + "<web-app>\n" + " <servlet>\n" + " <servlet-name>JnlpDownloadServlet</servlet-name>\n" + " <servlet-class>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class>\n" + " </servlet>\n" + " <servlet-mapping>\n" + " <servlet-name>JnlpDownloadServlet</servlet-name>\n" + " <url-pattern>*.jnlp</url-pattern>\n" + " </servlet-mapping>\n" + " <servlet-mapping>\n" + " <servlet-name>JnlpDownloadServlet</servlet-name>\n" + " <url-pattern>*.jar</url-pattern>\n" + " </servlet-mapping>\n" + " <mime-mapping>\n" + " <extension>jnlp</extension>\n" + " <mime-type>application/x-java-jnlp-file</mime-type>\n" + " </mime-mapping>\n" + "</web-app>\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; } }, "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)) { String codenamebase = theJar.getManifest().getMainAttributes().getValue("OpenIDE-Module"); if (codenamebase == null) { throw new IOException("Not a NetBeans Module: " + jar); } { int slash = codenamebase.indexOf('/'); if (slash >= 0) { codenamebase = codenamebase.substring(0, slash); } } String dashcnb = codenamebase.replace('.', '-'); buff.append(" <extension name='").append(codenamebase).append("' href='").append(masterPrefix) .append(dashcnb).append(".jnlp' />\n"); } } return buff.toString(); } private List<SignJar.JarsConfig> buildSignJarJarsConfigs(List<JarsConfig> jarsConfigs) { List<SignJar.JarsConfig> signJarJarsConfigs = new ArrayList<SignJar.JarsConfig>(); 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<Property> signJarManifestAttributes = new ArrayList<Property>(); 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<String, String> jarsConfigManifestAttributes = manifestEntries.getExtraAttributes(); if (jarsConfigManifestAttributes != null) { for (Map.Entry<String, String> entry : jarsConfigManifestAttributes.entrySet()) { signJarManifestAttributes.add(createAntProperty(entry.getKey(), entry.getValue())); } } List<String> jarsConfigRemoveAttributes = manifestEntries.getRemoveAttributes(); if (jarsConfigRemoveAttributes == null) { manifestEntries.setRemoveAttributes(jarsConfigRemoveAttributes = new ArrayList<String>()); } 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; } }