I didn't find a solution for this issue. Even tried to fix http://jira.codehaus.org/browse/MWEBSTART-224 but this defect is beyond my understanding. Also, I wanted to write a maven plugin to handle manifest manipulation, but it appeared to be too bureaucratic for me (see https://maven.apache.org/guides/mini/guide-central-repository-upload.html)
Therefore, I've decided to write my own solution and post here for future reference (hope it helps somebody else).
Briefly speaking, I have broken down my building process in different steps:
Compile and assemble: handled by webstart-maven-plugin
Add manifest attributes: handled by exec-maven-plugin running my custom class codesigning.AddManifestAttributes
Unsing and sing archives: handled by maven-jarsigner-plugin
Here is how my pom.xml looks like:
<plugin>
<groupId>org.codehaus.mojo.webstart</groupId>
<artifactId>webstart-maven-plugin</artifactId>
...
<configuration>
<libPath>plugins</libPath>
<makeArchive>false</makeArchive>
...
</configuration>
</plugin>
<!-- Adds manifest attributes to every file in a single directory -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<!-- Add manifest attributes to all files in a given location using the JDK 'jar umf' command line -->
<mainClass>codesigning.AddManifestAttributes</mainClass>
<arguments>
<!-- The first argument indicates a single directory where the files are located -->
<argument>${project.basedir}/target/jnlp/plugins</argument>
<!-- The other arguments indicates the manifest attributes to be added to each file -->
<argument>Permissions: all-permissions</argument>
<argument>Codebase: *</argument>
<argument>Trusted-Library: true</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<!-- Unsing and sign all java archives. You can also use the command line -> mvn jarsigner:sign -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
<executions>
<execution>
<id>sign</id>
<phase>install</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<configuration>
<archiveDirectory>${project.basedir}/target/jnlp/plugins</archiveDirectory>
<!-- Indicates whether existing signatures should be removed from the processed JAR files prior to signing them. If enabled, the resulting JAR will appear as being signed only once. -->
<removeExistingSignatures>true</removeExistingSignatures>
...
</configuration>
</plugin>
Here is how codesigning.AddManifestAttributes looks like:
package codesigning;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AddManifestAttributes {
private static Logger logger = Logger.getLogger(AddManifestAttributes.class.getName());
/**
* This application adds manifest attributes to every file in a single directory.
*
* arguments[0]: Directory where files to be updated are located
* arguments[1..]: Attributes to be added to manifest
*
* @param arguments
*/
public static void main(String[] arguments) {
String arquivesStringPath = arguments[0];
logger.info("Atempting to update archives located at: " + arquivesStringPath);
String manifestAddition = getManifestContent(arguments);
logger.info("Manifest content to be added:\n " + manifestAddition);
logger.info("Creating temporary manifest file");
File manifestFile = null;
try {
manifestFile = createsTemporaryManifestFile(manifestAddition);
logger.info("Temporary manifest file has been created at: " + manifestFile.getAbsolutePath());
} catch (IOException ioe) {
logger.log(Level.SEVERE, "Error when creating temporary manifest file. Message: " + ioe.getMessage());
}
logger.info("Reading files from: " + arquivesStringPath);
File arquivesPath = new File(arquivesStringPath);
if (arquivesPath.exists() && arquivesPath.isDirectory()) {
File[] files = arquivesPath.listFiles();
for (File f : files) {
try {
logger.info("Adding attributes from manifest [".concat(manifestFile.getAbsolutePath()).concat("] into [").concat(f.getAbsolutePath()).concat("]"));
logger.info(addManifestAttributes(manifestFile, f));
} catch (Exception e) {
logger.log(Level.SEVERE, "Error when unsigning archive [" + f.getAbsolutePath() + "]. Message: " + e.getMessage());
}
}
}
}
/**
* Breaks down an array of strings (starting from position [1]) in several lines.
* @param args
* @return String in manifest format
*/
private static String getManifestContent(String[] args) {
StringBuffer result = new StringBuffer();
for (int i = 1; i < args.length; i++) {
result.append(args[i]);
result.append("\n");
}
return result.toString();
}
/**
* Creates a temporary manifest file
* @return File pointing to the temporary manifest file created
* @throws IOException
*/
private static File createsTemporaryManifestFile(String content) throws IOException {
File file = File.createTempFile("UnsignArchiveTempManifest", ".mf");
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
return file;
}
/**
* Adds the attributes from <i>manifestFile</i> into <i>jarFile</i> using
* the jar tool included in the JDK issuing the command line
*
* <pre>
* jar cfm jar-file manifest-addition input-file(s)
* </pre>
*
* . More details at:
* http://docs.oracle.com/javase/tutorial/deployment/jar/modman.html
*
* @param manifestFile
* @param jarFile
* @return The output from the command line execution
* @throws IOException
*/
private static String addManifestAttributes(File manifestFile, File jarFile) throws IOException {
StringBuffer result = new StringBuffer();
/*
* This class is meant to run with maven which depends on JAVA_HOME
* environment variable (see http://maven.apache.org/download.cgi).
* Therefore it is reasonable to JAVA_HOME as a dependency to this
* class.
*/
String commandLine = System.getenv("JAVA_HOME").concat(File.separator).concat("bin").concat(File.separator).concat("jar");
ProcessBuilder processBuilder = new ProcessBuilder(commandLine, "ufm", jarFile.getAbsolutePath(), manifestFile.getAbsolutePath());
logger.info("Executing command line: " + commandLine + " ufm " + jarFile.getAbsolutePath() + " " + manifestFile.getAbsolutePath());
Process process = processBuilder.start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s = null;
while ((s = stdInput.readLine()) != null) {
result.append(s);
}
while ((s = stdError.readLine()) != null) {
result.append(s);
}
return result.toString();
}
}