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