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