blob: 0c95594f7534f9e7cd7c866e5c6e4f8e508c7eda [file] [log] [blame]
/*
* $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