Domanda

I'm in the middle of a fairly complex Java Web Start Application project. Briefly speaking, I've managed to assemble a bundle with everything I need following the file structure below:

--[PROJECT_ROOT]
  |--...
  |--jnlp
     |--...
     |--plugins
        |--[DEPENDENCY_01.JAR]
        |--[DEPENDENCY_02.JAR]
        |--...

Currently, my pom.xml instructs maven to place all project dependencies into: [PROJECT_ROOT]/jnlp/plugins

I need to tell maven to add the attribute "Trusted-Library: true" to the manifest of all .jar files located at [PROJECT_ROOT]/jnlp/plugins

Does anybody know how to do this?

È stato utile?

Soluzione

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();
    }

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top