/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.utility; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import org.eclipse.persistence.tools.workbench.utility.io.FileTools; import org.eclipse.persistence.tools.workbench.utility.string.StringTools; /** * This class parses most of the necessary information from a specified * class's manifest. * The manifest is built and stored in a file (META_INF/MANIFEST.MF) * in the class's JAR during the build process. * * User's of this class must provide a Java class from which * the JAR file is determined. They also must provide an implementation of * ManifestDefaults for when the JAR and/or the manifest cannot be resolved. */ public class ManifestInterrogator { /** * Defaults for when the Java class is not found * within a JAR or the JAR has no manifest. */ private Defaults defaults; /** * This is determined from the specified Java class. * It will be null if the class is NOT in a JAR. */ private String jarFileName; /** Hold the manifest so we can get stuff from it as needed. */ private Manifest manifest; /** Names of attributes stored in the JAR file manifest. */ private static final Attributes.Name RELEASE_DESIGNATION = new Attributes.Name("Release-Designation"); private static final Attributes.Name LIBRARY_DESIGNATION = new Attributes.Name("Library-Designation"); // ********** constructor/initialization ********** /** * Construct a manifest interrogator for the specified class. * If the manifest is unavailable, use the specified defaults. */ public ManifestInterrogator(Class javaClass, Defaults defaults) { super(); this.defaults = defaults; this.initialize(javaClass); } private void initialize(Class javaClass) { this.jarFileName = this.buildJarFileName(javaClass); this.manifest = this.buildManifest(); } /** * Return the "full" name of the specified Java class's JAR file, * either fully-qualified or with a path relative to the current * working directory; e.g. "C:/orahome/toplink/jlib/toplinkmw.jar" * or "jlib/toplinkmw.jar". * Return null if the JAR cannot be determined. */ protected String buildJarFileName(Class javaClass) { URL url = Classpath.convertToResource(javaClass); if (url.getProtocol().equalsIgnoreCase("file")) { return null; // the class is NOT in a JAR } // if the class is in a JAR, the URL will look something like this: // jar:file:/C:/jdk/1.4.2_04/jre/lib/rt.jar!/java/lang/String.class File file; try { file = FileTools.buildFile(url); } catch (URISyntaxException ex) { throw new RuntimeException(ex); } return file.getAbsolutePath().substring(0, file.getAbsolutePath().indexOf('!')); } /** * Build and return the application's manifest. */ private Manifest buildManifest() { JarFile jarFile = this.buildJarFile(); if (jarFile == null) { // if there is no JAR file, use an empty manifest return new Manifest(); } try { Manifest result = jarFile.getManifest(); if (result == null) { // if there is no manifest in the JAR, use an empty manifest return new Manifest(); } return result; } catch (IOException ex) { throw new RuntimeException(ex); } } /** * Build and return the application's JAR file. If the JAR file cannot * be determined, return null. */ private JarFile buildJarFile() { if (this.jarFileName == null) { return null; } try { return new JarFile(this.jarFileName); } catch (IOException ex) { throw new RuntimeException(ex); } } // ********** public API ********** /** * Return the value of the specified attribute. * Return null if the attribute is not found or empty. */ public String getMainAttributeValue(Attributes.Name name) { return getMainAttributeValue(name, null); } /** * Return the value of the specified attribute. * Return the specified default value if the attribute * is not found or empty. */ public String getMainAttributeValue(Attributes.Name name, String defaultValue) { String result = this.manifest.getMainAttributes().getValue(name); if (StringTools.stringIsEmpty(result)) { return defaultValue; } return result; } /** * Return false if the application is being executed from a JAR file. */ public boolean isDevelopmentMode() { return this.jarFileName == null; } /** * Concatenate the Specification Title, and * the Library Designation, as derived from the JAR file manifest. */ public String getFullProductName() { return this.getSpecificationVendor() + " " + this.getProductName(); } /** * Return the Specification Title, as derived from the JAR file manifest. */ public String getProductName() { return this.getMainAttributeValue(Attributes.Name.SPECIFICATION_TITLE, this.defaults.defaultSpecificationTitle()); } /** * Return the Specification Vendor, as derived from the JAR file manifest. */ public String getSpecificationVendor() { return this.getMainAttributeValue(Attributes.Name.SPECIFICATION_VENDOR, this.defaults.defaultSpecificationVendor()); } /** * Return the Library Designation, as derived from the JAR file manifest. */ public String getShortProductName() { return this.getMainAttributeValue(LIBRARY_DESIGNATION, this.defaults.defaultLibraryDesignation()); } /** * Return the Specification Version, as derived from the JAR file manifest. */ public String getVersionNumber() { return this.getMainAttributeValue(Attributes.Name.SPECIFICATION_VERSION, this.defaults.defaultSpecificationVersion()); } /** * Strip the build number off the end of the Implementation Version. */ public String getBuildNumber() { if (this.isDevelopmentMode()) { return "<dev>"; } String specVersion = this.getVersionNumber(); String impVersion = this.getMainAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION, this.defaults.defaultImplementationVersion()); return impVersion.substring(specVersion.length() + 1); } /** * Return the Release Designation, as derived from the JAR file manifest. */ public String getReleaseDesignation() { return this.getMainAttributeValue(RELEASE_DESIGNATION, this.defaults.defaultReleaseDesignation()); } // ********** nested interface ********** /** * Users of ManifestInterrogator must provide an implementation of this * interface. */ public interface Defaults { /** * Return the default to be used when a manifest is unavailable. */ String defaultSpecificationTitle(); /** * Return the default to be used when a manifest is unavailable. */ String defaultSpecificationVendor(); /** * Return the default to be used when a manifest is unavailable. */ String defaultReleaseDesignation(); /** * Return the default to be used when a manifest is unavailable. */ String defaultLibraryDesignation(); /** * Return the default to be used when a manifest is unavailable. */ String defaultSpecificationVersion(); /** * Return the default to be used when a manifest is unavailable. */ String defaultImplementationVersion(); } }