如何使用maven将清单属性添加到多个.jars?

时间:2014-03-14 16:03:03

标签: maven maven-2 maven-3

我正处于相当复杂的Java Web Start应用程序项目中。简而言之,我已经设法在下面的文件结构中组装了我需要的所有内容:

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

目前,我的pom.xml指示maven将所有项目依赖项放入:[PROJECT_ROOT] / jnlp / plugins

我需要告诉maven将属性“Trusted-Library:true”添加到位于[PROJECT_ROOT] / jnlp / plugins

的所有.jar文件的清单中

有人知道怎么做吗?

1 个答案:

答案 0 :(得分:2)

我找不到解决此问题的方法。甚至试图修复http://jira.codehaus.org/browse/MWEBSTART-224,但这个缺陷超出了我的理解范围。另外,我想写一个maven插件来处理清单操作,但它对我来说似乎太官僚了(见https://maven.apache.org/guides/mini/guide-central-repository-upload.html

因此,我决定编写自己的解决方案,并在此发布以供将来参考(希望它能帮助其他人)。

简单地说,我已经在不同的步骤中打破了我的构建过程:

  • 编译和汇编:由webstart-maven-plugin处理

  • 添加清单属性:由运行我的自定义类的exec-maven-plugin处理.ignign.AddManifestAttributes

  • 取消和唱歌档案:由maven-jarsigner-plugin处理

以下是我的pom.xml的样子:

<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>

以下是codesigning.AddManifestAttributes的样子:

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

}