1 /* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/util/VersionInfo.java $ 3 * $Revision: 554888 $ 4 * $Date: 2007-07-10 02:46:36 -0700 (Tue, 10 Jul 2007) $ 5 * 6 * ==================================================================== 7 * Licensed to the Apache Software Foundation (ASF) under one 8 * or more contributor license agreements. See the NOTICE file 9 * distributed with this work for additional information 10 * regarding copyright ownership. The ASF licenses this file 11 * to you under the Apache License, Version 2.0 (the 12 * "License"); you may not use this file except in compliance 13 * with the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, 18 * software distributed under the License is distributed on an 19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20 * KIND, either express or implied. See the License for the 21 * specific language governing permissions and limitations 22 * under the License. 23 * ==================================================================== 24 * 25 * This software consists of voluntary contributions made by many 26 * individuals on behalf of the Apache Software Foundation. For more 27 * information on the Apache Software Foundation, please see 28 * <http://www.apache.org/>. 29 * 30 */ 31 32 package org.apache.http.util; 33 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.util.Map; 37 import java.util.Properties; 38 import java.util.ArrayList; 39 40 41 /** 42 * Provides access to version information for HTTP components. 43 * Instances of this class provide version information for a single module 44 * or informal unit, as explained 45 * <a href="http://wiki.apache.org/jakarta-httpclient/HttpComponents">here</a>. 46 * Static methods are used to extract version information from property 47 * files that are automatically packaged with HTTP component release JARs. 48 * <br/> 49 * All available version information is provided in strings, where 50 * the string format is informal and subject to change without notice. 51 * Version information is provided for debugging output and interpretation 52 * by humans, not for automated processing in applications. 53 * 54 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> 55 * @author and others 56 */ 57 public class VersionInfo { 58 59 /** A string constant for unavailable information. */ 60 public final static String UNAVAILABLE = "UNAVAILABLE"; 61 62 /** The filename of the version information files. */ 63 public final static String VERSION_PROPERTY_FILE = "version.properties"; 64 65 // the property names 66 public final static String PROPERTY_MODULE = "info.module"; 67 public final static String PROPERTY_RELEASE = "info.release"; 68 public final static String PROPERTY_TIMESTAMP = "info.timestamp"; 69 70 71 /** The package that contains the version information. */ 72 private final String infoPackage; 73 74 /** The module from the version info. */ 75 private final String infoModule; 76 77 /** The release from the version info. */ 78 private final String infoRelease; 79 80 /** The timestamp from the version info. */ 81 private final String infoTimestamp; 82 83 /** The classloader from which the version info was obtained. */ 84 private final String infoClassloader; 85 86 87 /** 88 * Instantiates version information. 89 * 90 * @param pckg the package 91 * @param module the module, or <code>null</code> 92 * @param release the release, or <code>null</code> 93 * @param time the build time, or <code>null</code> 94 * @param clsldr the class loader, or <code>null</code> 95 */ VersionInfo(String pckg, String module, String release, String time, String clsldr)96 protected VersionInfo(String pckg, String module, 97 String release, String time, String clsldr) { 98 if (pckg == null) { 99 throw new IllegalArgumentException 100 ("Package identifier must not be null."); 101 } 102 103 infoPackage = pckg; 104 infoModule = (module != null) ? module : UNAVAILABLE; 105 infoRelease = (release != null) ? release : UNAVAILABLE; 106 infoTimestamp = (time != null) ? time : UNAVAILABLE; 107 infoClassloader = (clsldr != null) ? clsldr : UNAVAILABLE; 108 } 109 110 111 /** 112 * Obtains the package name. 113 * The package name identifies the module or informal unit. 114 * 115 * @return the package name, never <code>null</code> 116 */ getPackage()117 public final String getPackage() { 118 return infoPackage; 119 } 120 121 /** 122 * Obtains the name of the versioned module or informal unit. 123 * This data is read from the version information for the package. 124 * 125 * @return the module name, never <code>null</code> 126 */ getModule()127 public final String getModule() { 128 return infoModule; 129 } 130 131 /** 132 * Obtains the release of the versioned module or informal unit. 133 * This data is read from the version information for the package. 134 * 135 * @return the release version, never <code>null</code> 136 */ getRelease()137 public final String getRelease() { 138 return infoRelease; 139 } 140 141 /** 142 * Obtains the timestamp of the versioned module or informal unit. 143 * This data is read from the version information for the package. 144 * 145 * @return the timestamp, never <code>null</code> 146 */ getTimestamp()147 public final String getTimestamp() { 148 return infoTimestamp; 149 } 150 151 /** 152 * Obtains the classloader used to read the version information. 153 * This is just the <code>toString</code> output of the classloader, 154 * since the version information should not keep a reference to 155 * the classloader itself. That could prevent garbage collection. 156 * 157 * @return the classloader description, never <code>null</code> 158 */ getClassloader()159 public final String getClassloader() { 160 return infoClassloader; 161 } 162 163 164 /** 165 * Provides the version information in human-readable format. 166 * 167 * @return a string holding this version information 168 */ toString()169 public String toString() { 170 StringBuffer sb = new StringBuffer 171 (20 + infoPackage.length() + infoModule.length() + 172 infoRelease.length() + infoTimestamp.length() + 173 infoClassloader.length()); 174 175 sb.append("VersionInfo(") 176 .append(infoPackage).append(':').append(infoModule); 177 178 // If version info is missing, a single "UNAVAILABLE" for the module 179 // is sufficient. Everything else just clutters the output. 180 if (!UNAVAILABLE.equals(infoRelease)) 181 sb.append(':').append(infoRelease); 182 if (!UNAVAILABLE.equals(infoTimestamp)) 183 sb.append(':').append(infoTimestamp); 184 185 sb.append(')'); 186 187 if (!UNAVAILABLE.equals(infoClassloader)) 188 sb.append('@').append(infoClassloader); 189 190 return sb.toString(); 191 } 192 193 194 /** 195 * Loads version information for a list of packages. 196 * 197 * @param pckgs the packages for which to load version info 198 * @param clsldr the classloader to load from, or 199 * <code>null</code> for the thread context classloader 200 * 201 * @return the version information for all packages found, 202 * never <code>null</code> 203 */ loadVersionInfo(String[] pckgs, ClassLoader clsldr)204 public final static VersionInfo[] loadVersionInfo(String[] pckgs, 205 ClassLoader clsldr) { 206 if (pckgs == null) { 207 throw new IllegalArgumentException 208 ("Package identifier list must not be null."); 209 } 210 211 ArrayList vil = new ArrayList(pckgs.length); 212 for (int i=0; i<pckgs.length; i++) { 213 VersionInfo vi = loadVersionInfo(pckgs[i], clsldr); 214 if (vi != null) 215 vil.add(vi); 216 } 217 218 return (VersionInfo[]) vil.toArray(new VersionInfo[vil.size()]); 219 } 220 221 222 /** 223 * Loads version information for a package. 224 * 225 * @param pckg the package for which to load version information, 226 * for example "org.apache.http". 227 * The package name should NOT end with a dot. 228 * @param clsldr the classloader to load from, or 229 * <code>null</code> for the thread context classloader 230 * 231 * @return the version information for the argument package, or 232 * <code>null</code> if not available 233 */ loadVersionInfo(final String pckg, ClassLoader clsldr)234 public final static VersionInfo loadVersionInfo(final String pckg, 235 ClassLoader clsldr) { 236 if (pckg == null) { 237 throw new IllegalArgumentException 238 ("Package identifier must not be null."); 239 } 240 241 if (clsldr == null) 242 clsldr = Thread.currentThread().getContextClassLoader(); 243 244 Properties vip = null; // version info properties, if available 245 try { 246 // org.apache.http becomes 247 // org/apache/http/version.properties 248 InputStream is = clsldr.getResourceAsStream 249 (pckg.replace('.', '/') + "/" + VERSION_PROPERTY_FILE); 250 if (is != null) { 251 try { 252 Properties props = new Properties(); 253 props.load(is); 254 vip = props; 255 } finally { 256 is.close(); 257 } 258 } 259 } catch (IOException ex) { 260 // shamelessly munch this exception 261 } 262 263 VersionInfo result = null; 264 if (vip != null) 265 result = fromMap(pckg, vip, clsldr); 266 267 return result; 268 } 269 270 271 /** 272 * Instantiates version information from properties. 273 * 274 * @param pckg the package for the version information 275 * @param info the map from string keys to string values, 276 * for example {@link java.util.Properties} 277 * @param clsldr the classloader, or <code>null</code> 278 * 279 * @return the version information 280 */ fromMap(String pckg, Map info, ClassLoader clsldr)281 protected final static VersionInfo fromMap(String pckg, Map info, 282 ClassLoader clsldr) { 283 if (pckg == null) { 284 throw new IllegalArgumentException 285 ("Package identifier must not be null."); 286 } 287 288 String module = null; 289 String release = null; 290 String timestamp = null; 291 292 if (info != null) { 293 module = (String) info.get(PROPERTY_MODULE); 294 if ((module != null) && (module.length() < 1)) 295 module = null; 296 297 release = (String) info.get(PROPERTY_RELEASE); 298 if ((release != null) && ((release.length() < 1) || 299 (release.equals("${pom.version}")))) 300 release = null; 301 302 timestamp = (String) info.get(PROPERTY_TIMESTAMP); 303 if ((timestamp != null) && 304 ((timestamp.length() < 1) || 305 (timestamp.equals("${mvn.timestamp}"))) 306 ) 307 timestamp = null; 308 } // if info 309 310 String clsldrstr = null; 311 if (clsldr != null) 312 clsldrstr = clsldr.toString(); 313 314 return new VersionInfo(pckg, module, release, timestamp, clsldrstr); 315 } 316 317 } // class VersionInfo 318