michael@0: /* michael@0: * ==================================================================== michael@0: * Licensed to the Apache Software Foundation (ASF) under one michael@0: * or more contributor license agreements. See the NOTICE file michael@0: * distributed with this work for additional information michael@0: * regarding copyright ownership. The ASF licenses this file michael@0: * to you under the Apache License, Version 2.0 (the michael@0: * "License"); you may not use this file except in compliance michael@0: * with the License. You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, michael@0: * software distributed under the License is distributed on an michael@0: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY michael@0: * KIND, either express or implied. See the License for the michael@0: * specific language governing permissions and limitations michael@0: * under the License. michael@0: * ==================================================================== michael@0: * michael@0: * This software consists of voluntary contributions made by many michael@0: * individuals on behalf of the Apache Software Foundation. For more michael@0: * information on the Apache Software Foundation, please see michael@0: * . michael@0: * michael@0: */ michael@0: michael@0: package ch.boye.httpclientandroidlib.util; michael@0: michael@0: import java.io.IOException; michael@0: import java.io.InputStream; michael@0: import java.util.Map; michael@0: import java.util.Properties; michael@0: import java.util.ArrayList; michael@0: michael@0: michael@0: /** michael@0: * Provides access to version information for HTTP components. michael@0: * Static methods are used to extract version information from property michael@0: * files that are automatically packaged with HTTP component release JARs. michael@0: *
michael@0: * All available version information is provided in strings, where michael@0: * the string format is informal and subject to change without notice. michael@0: * Version information is provided for debugging output and interpretation michael@0: * by humans, not for automated processing in applications. michael@0: * michael@0: * @since 4.0 michael@0: */ michael@0: public class VersionInfo { michael@0: michael@0: /** A string constant for unavailable information. */ michael@0: public final static String UNAVAILABLE = "UNAVAILABLE"; michael@0: michael@0: /** The filename of the version information files. */ michael@0: public final static String VERSION_PROPERTY_FILE = "version.properties"; michael@0: michael@0: // the property names michael@0: public final static String PROPERTY_MODULE = "info.module"; michael@0: public final static String PROPERTY_RELEASE = "info.release"; michael@0: public final static String PROPERTY_TIMESTAMP = "info.timestamp"; michael@0: michael@0: michael@0: /** The package that contains the version information. */ michael@0: private final String infoPackage; michael@0: michael@0: /** The module from the version info. */ michael@0: private final String infoModule; michael@0: michael@0: /** The release from the version info. */ michael@0: private final String infoRelease; michael@0: michael@0: /** The timestamp from the version info. */ michael@0: private final String infoTimestamp; michael@0: michael@0: /** The classloader from which the version info was obtained. */ michael@0: private final String infoClassloader; michael@0: michael@0: michael@0: /** michael@0: * Instantiates version information. michael@0: * michael@0: * @param pckg the package michael@0: * @param module the module, or null michael@0: * @param release the release, or null michael@0: * @param time the build time, or null michael@0: * @param clsldr the class loader, or null michael@0: */ michael@0: protected VersionInfo(String pckg, String module, michael@0: String release, String time, String clsldr) { michael@0: if (pckg == null) { michael@0: throw new IllegalArgumentException michael@0: ("Package identifier must not be null."); michael@0: } michael@0: michael@0: infoPackage = pckg; michael@0: infoModule = (module != null) ? module : UNAVAILABLE; michael@0: infoRelease = (release != null) ? release : UNAVAILABLE; michael@0: infoTimestamp = (time != null) ? time : UNAVAILABLE; michael@0: infoClassloader = (clsldr != null) ? clsldr : UNAVAILABLE; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Obtains the package name. michael@0: * The package name identifies the module or informal unit. michael@0: * michael@0: * @return the package name, never null michael@0: */ michael@0: public final String getPackage() { michael@0: return infoPackage; michael@0: } michael@0: michael@0: /** michael@0: * Obtains the name of the versioned module or informal unit. michael@0: * This data is read from the version information for the package. michael@0: * michael@0: * @return the module name, never null michael@0: */ michael@0: public final String getModule() { michael@0: return infoModule; michael@0: } michael@0: michael@0: /** michael@0: * Obtains the release of the versioned module or informal unit. michael@0: * This data is read from the version information for the package. michael@0: * michael@0: * @return the release version, never null michael@0: */ michael@0: public final String getRelease() { michael@0: return infoRelease; michael@0: } michael@0: michael@0: /** michael@0: * Obtains the timestamp of the versioned module or informal unit. michael@0: * This data is read from the version information for the package. michael@0: * michael@0: * @return the timestamp, never null michael@0: */ michael@0: public final String getTimestamp() { michael@0: return infoTimestamp; michael@0: } michael@0: michael@0: /** michael@0: * Obtains the classloader used to read the version information. michael@0: * This is just the toString output of the classloader, michael@0: * since the version information should not keep a reference to michael@0: * the classloader itself. That could prevent garbage collection. michael@0: * michael@0: * @return the classloader description, never null michael@0: */ michael@0: public final String getClassloader() { michael@0: return infoClassloader; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Provides the version information in human-readable format. michael@0: * michael@0: * @return a string holding this version information michael@0: */ michael@0: public String toString() { michael@0: StringBuffer sb = new StringBuffer michael@0: (20 + infoPackage.length() + infoModule.length() + michael@0: infoRelease.length() + infoTimestamp.length() + michael@0: infoClassloader.length()); michael@0: michael@0: sb.append("VersionInfo(") michael@0: .append(infoPackage).append(':').append(infoModule); michael@0: michael@0: // If version info is missing, a single "UNAVAILABLE" for the module michael@0: // is sufficient. Everything else just clutters the output. michael@0: if (!UNAVAILABLE.equals(infoRelease)) michael@0: sb.append(':').append(infoRelease); michael@0: if (!UNAVAILABLE.equals(infoTimestamp)) michael@0: sb.append(':').append(infoTimestamp); michael@0: michael@0: sb.append(')'); michael@0: michael@0: if (!UNAVAILABLE.equals(infoClassloader)) michael@0: sb.append('@').append(infoClassloader); michael@0: michael@0: return sb.toString(); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Loads version information for a list of packages. michael@0: * michael@0: * @param pckgs the packages for which to load version info michael@0: * @param clsldr the classloader to load from, or michael@0: * null for the thread context classloader michael@0: * michael@0: * @return the version information for all packages found, michael@0: * never null michael@0: */ michael@0: public final static VersionInfo[] loadVersionInfo(String[] pckgs, michael@0: ClassLoader clsldr) { michael@0: if (pckgs == null) { michael@0: throw new IllegalArgumentException michael@0: ("Package identifier list must not be null."); michael@0: } michael@0: michael@0: ArrayList vil = new ArrayList(pckgs.length); michael@0: for (int i=0; inull for the thread context classloader michael@0: * michael@0: * @return the version information for the argument package, or michael@0: * null if not available michael@0: */ michael@0: public final static VersionInfo loadVersionInfo(final String pckg, michael@0: ClassLoader clsldr) { michael@0: if (pckg == null) { michael@0: throw new IllegalArgumentException michael@0: ("Package identifier must not be null."); michael@0: } michael@0: michael@0: if (clsldr == null) michael@0: clsldr = Thread.currentThread().getContextClassLoader(); michael@0: michael@0: Properties vip = null; // version info properties, if available michael@0: try { michael@0: // ch.boye.httpclientandroidlib becomes michael@0: // org/apache/http/version.properties michael@0: InputStream is = clsldr.getResourceAsStream michael@0: (pckg.replace('.', '/') + "/" + VERSION_PROPERTY_FILE); michael@0: if (is != null) { michael@0: try { michael@0: Properties props = new Properties(); michael@0: props.load(is); michael@0: vip = props; michael@0: } finally { michael@0: is.close(); michael@0: } michael@0: } michael@0: } catch (IOException ex) { michael@0: // shamelessly munch this exception michael@0: } michael@0: michael@0: VersionInfo result = null; michael@0: if (vip != null) michael@0: result = fromMap(pckg, vip, clsldr); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Instantiates version information from properties. michael@0: * michael@0: * @param pckg the package for the version information michael@0: * @param info the map from string keys to string values, michael@0: * for example {@link java.util.Properties} michael@0: * @param clsldr the classloader, or null michael@0: * michael@0: * @return the version information michael@0: */ michael@0: protected final static VersionInfo fromMap(String pckg, Map info, michael@0: ClassLoader clsldr) { michael@0: if (pckg == null) { michael@0: throw new IllegalArgumentException michael@0: ("Package identifier must not be null."); michael@0: } michael@0: michael@0: String module = null; michael@0: String release = null; michael@0: String timestamp = null; michael@0: michael@0: if (info != null) { michael@0: module = (String) info.get(PROPERTY_MODULE); michael@0: if ((module != null) && (module.length() < 1)) michael@0: module = null; michael@0: michael@0: release = (String) info.get(PROPERTY_RELEASE); michael@0: if ((release != null) && ((release.length() < 1) || michael@0: (release.equals("${pom.version}")))) michael@0: release = null; michael@0: michael@0: timestamp = (String) info.get(PROPERTY_TIMESTAMP); michael@0: if ((timestamp != null) && michael@0: ((timestamp.length() < 1) || michael@0: (timestamp.equals("${mvn.timestamp}"))) michael@0: ) michael@0: timestamp = null; michael@0: } // if info michael@0: michael@0: String clsldrstr = null; michael@0: if (clsldr != null) michael@0: clsldrstr = clsldr.toString(); michael@0: michael@0: return new VersionInfo(pckg, module, release, timestamp, clsldrstr); michael@0: } michael@0: michael@0: } // class VersionInfo