1 /*
2 ProgramVersionUtils.java
3 Creation date : 18/11/2010
4 Copyright © Benjamin Croizet (graffity2199@yahoo.fr)
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 or GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received copies of the GNU General Public License
18 and GNU Lesser General Public License along with this program;
19 if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 http://www.fsf.org/licensing/licenses/gpl.html
22 http://www.gnu.org/licenses/lgpl.html
23 */
24
25 package net.sourceforge.plantumldependency.commoncli.utils.version;
26
27 import static java.lang.ClassLoader.getSystemClassLoader;
28 import static java.lang.Thread.currentThread;
29 import static java.util.logging.Level.FINE;
30 import static java.util.logging.Level.SEVERE;
31 import static java.util.logging.Logger.getLogger;
32 import static net.sourceforge.plantumldependency.common.constants.CommonConstants.MINUS_ONE_RETURN_CODE;
33 import static net.sourceforge.plantumldependency.common.utils.check.ParameterCheckerUtils.checkNull;
34 import static net.sourceforge.plantumldependency.common.utils.check.ParameterCheckerUtils.checkNullOrEmpty;
35 import static net.sourceforge.plantumldependency.common.utils.file.FileUtils.closeCloseable;
36 import static net.sourceforge.plantumldependency.common.utils.log.LogUtils.buildLogString;
37 import static net.sourceforge.plantumldependency.common.utils.string.StringUtils.isNotEmpty;
38 import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.PROTECTED_DOT_REGEXP;
39 import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.DATE_FORMAT_ERROR;
40 import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.EMPTY_ARGUMENT_ERROR;
41 import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.MISSING_PROPERTY_ERROR;
42 import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.MISSING_PROPERTY_FILE_ERROR;
43 import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_VERSION_PARSING2_ERROR;
44 import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_VERSION_PARSING_ERROR;
45 import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.PROPERTY_SPECIFIED_FINE;
46 import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.SNAPSHOT_VERSION_SPECIFIED_FINE;
47
48 import java.io.File;
49 import java.io.FileInputStream;
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.text.DateFormat;
53 import java.text.ParseException;
54 import java.text.SimpleDateFormat;
55 import java.util.Date;
56 import java.util.Properties;
57 import java.util.logging.Logger;
58
59 import net.sourceforge.plantumldependency.commoncli.exception.MissingPropertyException;
60 import net.sourceforge.plantumldependency.commoncli.program.version.ProgramVersion;
61 import net.sourceforge.plantumldependency.commoncli.program.version.impl.ProgramVersionImpl;
62
63 /**
64 * The class utilities simplifying some {@link ProgramVersion} tasks.
65 *
66 * @author Benjamin Croizet (<a href="mailto:graffity2199@yahoo.fr>graffity2199@yahoo.fr</a>)
67 * @since 1.3.0
68 * @version 1.3.0
69 */
70 public abstract class ProgramVersionUtils {
71
72 /** The class logger. */
73 private static final transient Logger LOGGER = getLogger(ProgramVersionUtils.class.getName());
74
75 /** Build time stamp property constant. */
76 public static final String BUILD_TIMESTAMP_PROPERTY = "build.timestamp";
77
78 /** Build time stamp format property constant. */
79 public static final String BUILD_TIMESTAMP_FORMAT_PROPERTY = "maven.build.timestamp.format";
80
81 /** Version property constant. */
82 public static final String VERSION_PROPERTY = "version";
83
84 /** The string representing a snapshot version. */
85 public static final String SNAPSHOT_VERSION = "-SNAPSHOT";
86
87 /**
88 * The integer representing the number of digit expected while parsing a program version string.
89 */
90 private static final int VERSION_NUMBER = 3;
91
92 /**
93 * Creates a {@link ProgramVersion} instance from a properties {@link Properties}.
94 * <p>
95 * The following properties must exist in the properties in order to correctly create the
96 * {@link ProgramVersion} instance :<br>
97 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
98 * form matching the build time stamp format property value.<br>
99 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
100 * have a form matching the {@link java.text.DateFormat}.<br>
101 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
102 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
103 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
104 * </p>
105 *
106 * @param properties
107 * the properties {@link Properties} instance to read the program version from,
108 * mustn't be <code>null</code>.
109 * @return the {@link ProgramVersion} instance created from the property file attributes.
110 * @throws ParseException
111 * if a property value can't be parsed.
112 * @throws MissingPropertyException
113 * if one of the three needed property is missing.
114 * @since 1.3.0
115 */
116 public static ProgramVersion createProgramVersionFromProperties(final Properties properties) throws ParseException,
117 MissingPropertyException {
118 return createProgramVersionFromProperties(properties, PROTECTED_DOT_REGEXP);
119 }
120
121 /**
122 * Creates a {@link ProgramVersion} instance from a properties {@link Properties}.
123 * <p>
124 * The following properties must exist in the properties in order to correctly create the
125 * {@link ProgramVersion} instance :<br>
126 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
127 * form matching the build time stamp format property value.<br>
128 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
129 * have a form matching the {@link java.text.DateFormat}.<br>
130 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
131 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
132 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
133 * </p>
134 *
135 * @param properties
136 * the properties {@link Properties} instance to read the program version from,
137 * mustn't be <code>null</code>.
138 * @param versionSeparatorRegexp
139 * the version separator to be used for parsing the
140 * {@link ProgramVersionUtils#VERSION_PROPERTY} property, mustn't be
141 * <code>null</code>.
142 * @return the {@link ProgramVersion} instance created from the property file attributes.
143 * @throws ParseException
144 * if a property value can't be parsed.
145 * @throws MissingPropertyException
146 * if one of the three needed property is missing.
147 * @since 1.3.0
148 */
149 public static ProgramVersion createProgramVersionFromProperties(final Properties properties,
150 final String versionSeparatorRegexp) throws ParseException, MissingPropertyException {
151 checkNull(properties, buildLogString(EMPTY_ARGUMENT_ERROR, "properties"));
152 checkNullOrEmpty(versionSeparatorRegexp, buildLogString(EMPTY_ARGUMENT_ERROR, "versionSeparatorRegexp"));
153
154 ProgramVersion programVersion = null;
155
156 final String buildTimestamp = getPropertyValue(properties, BUILD_TIMESTAMP_PROPERTY);
157 final String buildTimestampFormat = getPropertyValue(properties, BUILD_TIMESTAMP_FORMAT_PROPERTY);
158
159 try {
160 final DateFormat dateFormat = new SimpleDateFormat(buildTimestampFormat);
161 final Date buildDate = dateFormat.parse(buildTimestamp);
162
163 final String version = getPropertyValue(properties, VERSION_PROPERTY);
164 programVersion = createProgramVersionFromStringAndDate(version, versionSeparatorRegexp, buildDate);
165 } catch (final IllegalArgumentException e) {
166 LOGGER.log(SEVERE, buildLogString(DATE_FORMAT_ERROR, buildTimestampFormat), e);
167 throw new ParseException(buildLogString(DATE_FORMAT_ERROR, buildTimestampFormat), MINUS_ONE_RETURN_CODE);
168 } catch (final ParseException e) {
169 LOGGER.log(SEVERE, buildLogString(DATE_FORMAT_ERROR, buildTimestampFormat), e);
170 throw new ParseException(buildLogString(DATE_FORMAT_ERROR, buildTimestampFormat), MINUS_ONE_RETURN_CODE);
171 }
172
173 return programVersion;
174 }
175
176 /**
177 * Creates a {@link ProgramVersion} instance from a file properties path.
178 * <p>
179 * The following properties must exist in the properties in order to correctly create the
180 * {@link ProgramVersion} instance :<br>
181 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
182 * form matching the build time stamp format property value.<br>
183 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
184 * have a form matching the {@link java.text.DateFormat}.<br>
185 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
186 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
187 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
188 * </p>
189 *
190 * @param propertiesFullPath
191 * the full path following the current OS of the property file, mustn't be
192 * <code>null</code>.
193 * @return the {@link ProgramVersion} instance created from the property file attributes.
194 * @throws IOException
195 * if any occurs when reading the property file.
196 * @throws ParseException
197 * if a property value can't be parsed.
198 * @throws MissingPropertyException
199 * if one of the three needed property is missing.
200 * @since 1.3.0
201 */
202 public static ProgramVersion createProgramVersionFromPropertiesFile(final String propertiesFullPath)
203 throws IOException, ParseException, MissingPropertyException {
204 return createProgramVersionFromPropertiesFile(propertiesFullPath, PROTECTED_DOT_REGEXP);
205 }
206
207 /**
208 * Creates a {@link ProgramVersion} instance from a file properties path.
209 * <p>
210 * The following properties must exist in the properties in order to correctly create the
211 * {@link ProgramVersion} instance :<br>
212 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
213 * form matching the build time stamp format property value.<br>
214 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
215 * have a form matching the {@link java.text.DateFormat}.<br>
216 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
217 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
218 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
219 * </p>
220 *
221 * @param propertiesFullPath
222 * the full path following the current OS of the property file, mustn't be
223 * <code>null</code>.
224 * @param versionSeparatorRegexp
225 * the version separator to be used for parsing the
226 * {@link ProgramVersionUtils#VERSION_PROPERTY} property, mustn't be
227 * <code>null</code>.
228 * @return the {@link ProgramVersion} instance created from the property file attributes.
229 * @throws IOException
230 * if any occurs when reading the property file.
231 * @throws ParseException
232 * if a property value can't be parsed.
233 * @throws MissingPropertyException
234 * if one of the three needed property is missing.
235 * @since 1.3.0
236 */
237 public static ProgramVersion createProgramVersionFromPropertiesFile(final String propertiesFullPath,
238 final String versionSeparatorRegexp) throws IOException, ParseException, MissingPropertyException {
239 checkNullOrEmpty(propertiesFullPath, buildLogString(EMPTY_ARGUMENT_ERROR, "propertiesFullPath"));
240 checkNullOrEmpty(versionSeparatorRegexp, buildLogString(EMPTY_ARGUMENT_ERROR, "versionSeparatorRegexp"));
241
242 ProgramVersion programVersion = null;
243
244 InputStream inputStream = null;
245 try {
246 final File propertyFile = new File(propertiesFullPath);
247 inputStream = new FileInputStream(propertyFile);
248 programVersion = createProgramVersionFromPropertiesFileInputStream(inputStream, versionSeparatorRegexp);
249 } finally {
250 closeCloseable(inputStream, propertiesFullPath);
251 }
252
253 return programVersion;
254 }
255
256 /**
257 * Creates a {@link ProgramVersion} instance from an {@link InputStream} which must be a
258 * property file.
259 * <p>
260 * The following properties must exist in the properties in order to correctly create the
261 * {@link ProgramVersion} instance :<br>
262 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
263 * form matching the build time stamp format property value.<br>
264 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
265 * have a form matching the {@link java.text.DateFormat}.<br>
266 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
267 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
268 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
269 * </p>
270 *
271 * @param propertiesFileInputStream
272 * the {@link InputStream} instance to read the program version properties from,
273 * mustn't be <code>null</code>.
274 * @return the {@link ProgramVersion} instance created from the property file attributes.
275 * @throws IOException
276 * if any occurs when reading the property file.
277 * @throws ParseException
278 * if a property value can't be parsed.
279 * @throws MissingPropertyException
280 * if one of the three needed property is missing.
281 * @since 1.3.0
282 */
283 public static ProgramVersion createProgramVersionFromPropertiesFileInputStream(
284 final InputStream propertiesFileInputStream) throws IOException, ParseException, MissingPropertyException {
285 return createProgramVersionFromPropertiesFileInputStream(propertiesFileInputStream, PROTECTED_DOT_REGEXP);
286 }
287
288 /**
289 * Creates a {@link ProgramVersion} instance from an {@link InputStream} which must be a
290 * property file.
291 * <p>
292 * The following properties must exist in the properties in order to correctly create the
293 * {@link ProgramVersion} instance :<br>
294 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
295 * form matching the build time stamp format property value.<br>
296 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
297 * have a form matching the {@link java.text.DateFormat}.<br>
298 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
299 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
300 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
301 * </p>
302 *
303 * @param propertiesFileInputStream
304 * the {@link InputStream} instance to read the program version properties from,
305 * mustn't be <code>null</code>.
306 * @param versionSeparatorRegexp
307 * the version separator to be used for parsing the
308 * {@link ProgramVersionUtils#VERSION_PROPERTY} property, mustn't be
309 * <code>null</code>.
310 * @return the {@link ProgramVersion} instance created from the property file attributes.
311 * @throws IOException
312 * if any occurs when reading the property file.
313 * @throws ParseException
314 * if a property value can't be parsed.
315 * @throws MissingPropertyException
316 * if one of the three needed property is missing.
317 * @since 1.3.0
318 */
319 public static ProgramVersion createProgramVersionFromPropertiesFileInputStream(
320 final InputStream propertiesFileInputStream, final String versionSeparatorRegexp) throws IOException,
321 ParseException, MissingPropertyException {
322 ProgramVersion programVersion = null;
323
324 if (propertiesFileInputStream != null) {
325 final Properties properties = new Properties();
326 properties.load(propertiesFileInputStream);
327 programVersion = createProgramVersionFromProperties(properties, versionSeparatorRegexp);
328 } else {
329 throw new IllegalArgumentException(buildLogString(EMPTY_ARGUMENT_ERROR, "propertiesFileInputStream"));
330 }
331
332 return programVersion;
333 }
334
335 /**
336 * Creates a {@link ProgramVersion} instance from a properties path which can be read by the
337 * specified class classloader.
338 * <p>
339 * The following properties must exist in the properties in order to correctly create the
340 * {@link ProgramVersion} instance :<br>
341 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
342 * form matching the build time stamp format property value.<br>
343 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
344 * have a form matching the {@link java.text.DateFormat}.<br>
345 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
346 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
347 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
348 * </p>
349 *
350 * @param propertiesFullPath
351 * the full path of the property file within the specified class classloader.
352 * @param clazz
353 * the {@link Class} to get the classloader from, mustn't be <code>null</code>.
354 * @return the {@link ProgramVersion} instance created from the property file attributes.
355 * @throws IOException
356 * if any occurs when reading the property file.
357 * @throws ParseException
358 * if a property value can't be parsed.
359 * @throws MissingPropertyException
360 * if one of the three needed property is missing.
361 * @since 1.3.0
362 */
363 public static ProgramVersion createProgramVersionFromPropertiesFileWithinClassClassloader(
364 final String propertiesFullPath, final Class < ? > clazz) throws IOException, ParseException,
365 MissingPropertyException {
366 return createProgramVersionFromPropertiesFileWithinClassloader(propertiesFullPath, PROTECTED_DOT_REGEXP,
367 clazz.getClassLoader());
368 }
369
370 /**
371 * Creates a {@link ProgramVersion} instance from a properties path which can be read by the
372 * classloader.
373 * <p>
374 * The following properties must exist in the properties in order to correctly create the
375 * {@link ProgramVersion} instance :<br>
376 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
377 * form matching the build time stamp format property value.<br>
378 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
379 * have a form matching the {@link java.text.DateFormat}.<br>
380 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
381 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
382 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
383 * </p>
384 *
385 * @param propertiesFullPath
386 * the full path of the property file within the classloader.
387 * @param versionSeparatorRegexp
388 * the version separator to be used for parsing the
389 * {@link ProgramVersionUtils#VERSION_PROPERTY} property, mustn't be
390 * <code>null</code>.
391 * @param classloader
392 * the {@link ClassLoader} to load the resource from, mustn't be <code>null</code>.
393 * @return the {@link ProgramVersion} instance created from the property file attributes.
394 * @throws IOException
395 * if any occurs when reading the property file.
396 * @throws ParseException
397 * if a property value can't be parsed.
398 * @throws MissingPropertyException
399 * if one of the three needed property is missing.
400 * @since 1.3.0
401 */
402 public static ProgramVersion createProgramVersionFromPropertiesFileWithinClassloader(
403 final String propertiesFullPath, final String versionSeparatorRegexp, final ClassLoader classloader)
404 throws IOException, ParseException, MissingPropertyException {
405 checkNullOrEmpty(propertiesFullPath, buildLogString(EMPTY_ARGUMENT_ERROR, "propertiesFullPath"));
406 checkNullOrEmpty(versionSeparatorRegexp, buildLogString(EMPTY_ARGUMENT_ERROR, "versionSeparatorRegexp"));
407 checkNull(classloader, buildLogString(EMPTY_ARGUMENT_ERROR, "classloader"));
408
409 ProgramVersion programVersion = null;
410
411 InputStream inputStream = null;
412 try {
413 inputStream = classloader.getResourceAsStream(propertiesFullPath);
414 if (inputStream != null) {
415 programVersion = createProgramVersionFromPropertiesFileInputStream(inputStream, versionSeparatorRegexp);
416 } else {
417 throw new IOException(buildLogString(MISSING_PROPERTY_FILE_ERROR, propertiesFullPath));
418 }
419 } finally {
420 closeCloseable(inputStream, propertiesFullPath);
421 }
422
423 return programVersion;
424 }
425
426 /**
427 * Creates a {@link ProgramVersion} instance from a properties path which can be read by the
428 * system classloader.
429 * <p>
430 * The following properties must exist in the properties in order to correctly create the
431 * {@link ProgramVersion} instance :<br>
432 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
433 * form matching the build time stamp format property value.<br>
434 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
435 * have a form matching the {@link java.text.DateFormat}.<br>
436 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
437 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
438 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
439 * </p>
440 *
441 * @param propertiesFullPath
442 * the full path of the property file within the system classloader.
443 * @return the {@link ProgramVersion} instance created from the property file attributes.
444 * @throws IOException
445 * if any occurs when reading the property file.
446 * @throws ParseException
447 * if a property value can't be parsed.
448 * @throws MissingPropertyException
449 * if one of the three needed property is missing.
450 * @since 1.3.0
451 */
452 public static ProgramVersion createProgramVersionFromPropertiesFileWithinSystemClassloader(
453 final String propertiesFullPath) throws IOException, ParseException, MissingPropertyException {
454 return createProgramVersionFromPropertiesFileWithinClassloader(propertiesFullPath, PROTECTED_DOT_REGEXP,
455 getSystemClassLoader());
456 }
457
458 /**
459 * Creates a {@link ProgramVersion} instance from a properties path which can be read by the
460 * thread classloader.
461 * <p>
462 * The following properties must exist in the properties in order to correctly create the
463 * {@link ProgramVersion} instance :<br>
464 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_PROPERTY}</i> where the value should have a
465 * form matching the build time stamp format property value.<br>
466 * <i>{@link ProgramVersionUtils#BUILD_TIMESTAMP_FORMAT_PROPERTY}</i> where the value should
467 * have a form matching the {@link java.text.DateFormat}.<br>
468 * <i>{@link ProgramVersionUtils#VERSION_PROPERTY} where the value should have a form matching
469 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
470 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.</i>
471 * </p>
472 *
473 * @param propertiesFullPath
474 * the full path of the property file within the thread classloader.
475 * @return the {@link ProgramVersion} instance created from the property file attributes.
476 * @throws IOException
477 * if any occurs when reading the property file.
478 * @throws ParseException
479 * if a property value can't be parsed.
480 * @throws MissingPropertyException
481 * if one of the three needed property is missing.
482 * @since 1.3.0
483 */
484 public static ProgramVersion createProgramVersionFromPropertiesFileWithinThreadClassloader(
485 final String propertiesFullPath) throws IOException, ParseException, MissingPropertyException {
486 return createProgramVersionFromPropertiesFileWithinClassloader(propertiesFullPath, PROTECTED_DOT_REGEXP,
487 currentThread().getContextClassLoader());
488 }
489
490 /**
491 * Creates a {@link ProgramVersion} instance from a {@link String}.
492 *
493 * @param programVersionString
494 * the program version as a {@link String} to parse, mustn't be <code>null</code> nor
495 * empty. Must have the form of "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)"
496 * or "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.
497 * @param versionSeparatorRegexp
498 * the version separator to be used for parsing the <code>programVersionString</code>
499 * , mustn't be <code>null</code>.
500 * @param programVersionDate
501 * the compilation date version to pass to the {@link ProgramVersion} instance as a
502 * {@link String}.
503 * @param programVersionDatePattern
504 * the program version date pattern to read the <code>programVersionDate</code>
505 * parameter, mustn't be <code>null</code>.
506 * @return the {@link ProgramVersion} instance created from the string.
507 * @throws ParseException
508 * if any exception occurs while reading or parsing the input string.
509 * @since 1.3.0
510 */
511 public static ProgramVersion createProgramVersionFromString(final String programVersionString,
512 final String versionSeparatorRegexp, final String programVersionDate, final String programVersionDatePattern)
513 throws ParseException {
514 checkNullOrEmpty(programVersionDate, buildLogString(EMPTY_ARGUMENT_ERROR, "programVersionDate"));
515 checkNullOrEmpty(programVersionDatePattern, buildLogString(EMPTY_ARGUMENT_ERROR, "programVersionDatePattern"));
516
517 final DateFormat dateFormat = new SimpleDateFormat(programVersionDatePattern);
518 final Date buildDate = dateFormat.parse(programVersionDate);
519
520 return createProgramVersionFromStringAndDate(programVersionString, versionSeparatorRegexp, buildDate);
521 }
522
523 /**
524 * Creates a {@link ProgramVersion} instance from a {@link String}.
525 *
526 * @param programVersionString
527 * the program version as a {@link String} to parse, mustn't be <code>null</code> nor
528 * empty. Must have the form of "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)"
529 * or "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator.
530 * @param versionSeparatorRegexp
531 * the version separator to be used for parsing the <code>programVersionString</code>
532 * , mustn't be <code>null</code>.
533 * @param programVersionDate
534 * the compilation date version to pass to the {@link ProgramVersion} instance.
535 * @return the {@link ProgramVersion} instance created from the string.
536 * @throws ParseException
537 * if any exception occurs while reading or parsing the input string.
538 * @since 1.3.0
539 */
540 public static ProgramVersion createProgramVersionFromStringAndDate(final String programVersionString,
541 final String versionSeparatorRegexp, final Date programVersionDate) throws ParseException {
542 checkNullOrEmpty(programVersionString, buildLogString(EMPTY_ARGUMENT_ERROR, "programVersionString"));
543 checkNullOrEmpty(versionSeparatorRegexp, buildLogString(EMPTY_ARGUMENT_ERROR, "versionSeparatorRegexp"));
544
545 final String version = removeSnapshot(programVersionString);
546
547 final boolean isSnapshot = !version.equals(programVersionString);
548 return createProgramVersionFromStringDateAndSnapshot(programVersionDate, version, versionSeparatorRegexp,
549 isSnapshot);
550 }
551
552 /**
553 * Creates a {@link ProgramVersion} instance from a {@link String}, a {@link Date} and a
554 * snapshot parameter.
555 *
556 * @param programVersionDate
557 * the program version {@link Date}, mustn't be <code>null</code>
558 * @param programVersionString
559 * the program version as a {@link String} to parse, mustn't be <code>null</code> nor
560 * empty. Must have the form of "majorNumber.minorNumber.revisionNumber" or
561 * "majorNumber-minorNumber-revisionNumber", following the separator.
562 * @param versionSeparatorRegexp
563 * the version separator to be used for parsing the <code>programVersionString</code>
564 * , mustn't be <code>null</code>.
565 * @param isSnapshot
566 * the <code>boolean</code> telling if the program version is a snapshot.
567 * @return the {@link ProgramVersion} instance created from the string and the passed parameter.
568 * @throws ParseException
569 * if any exception occurs while reading or parsing the input string.
570 * @since 1.3.0
571 */
572 private static ProgramVersion createProgramVersionFromStringDateAndSnapshot(final Date programVersionDate,
573 final String programVersionString, final String versionSeparatorRegexp, final boolean isSnapshot)
574 throws ParseException {
575 ProgramVersion programVersion = null;
576
577 final String[] versionNumbers = programVersionString.split(versionSeparatorRegexp);
578 if (versionNumbers.length == VERSION_NUMBER) {
579 try {
580 final Integer majorVersionNumber = Integer.valueOf(versionNumbers[0]);
581 final Integer minorVersionNumber = Integer.valueOf(versionNumbers[1]);
582 final Integer revisionVersionNumber = Integer.valueOf(versionNumbers[2]);
583 programVersion = new ProgramVersionImpl(majorVersionNumber.intValue(), minorVersionNumber.intValue(),
584 revisionVersionNumber.intValue(), programVersionDate, isSnapshot);
585 } catch (final NumberFormatException e) {
586 throw new ParseException(buildLogString(PROGRAM_VERSION_PARSING_ERROR, e.getMessage()), 0);
587 }
588 } else {
589 throw new ParseException(PROGRAM_VERSION_PARSING2_ERROR, 0);
590 }
591 return programVersion;
592 }
593
594 /**
595 * Gets the value of the property key in the properties instance, and throw an exception if not
596 * found.
597 *
598 * @param properties
599 * the {@link Properties} instance where to look into, mustn't be <code>null</code>.
600 * @param propertyKey
601 * the property key to look for, mustn't be empty.
602 * @return the value matching the <code>propertyKey</code> if found.
603 * @throws MissingPropertyException
604 * if the property value can't be found within the <code>properties</code> instance.
605 * @since 1.3.0
606 */
607 private static String getPropertyValue(final Properties properties, final String propertyKey)
608 throws MissingPropertyException {
609 final String propertyValue = (String) properties.get(propertyKey);
610 if (isNotEmpty(propertyValue)) {
611 LOGGER.log(FINE, buildLogString(PROPERTY_SPECIFIED_FINE, new String[] {propertyKey, propertyValue}));
612 } else {
613 throw new MissingPropertyException(buildLogString(MISSING_PROPERTY_ERROR, propertyKey));
614 }
615
616 return propertyValue;
617 }
618
619 /**
620 * Remove the {@link ProgramVersionUtils#SNAPSHOT_VERSION} from the program version string if
621 * found.
622 *
623 * @param programVersionString
624 * the program version string to parse, with a form matching
625 * "majorNumber.minorNumber.revisionNumber(-SNAPSHOT)" or
626 * "majorNumber-minorNumber-revisionNumber(-SNAPSHOT)", following the separator, can
627 * be <code>null</code> of empty.
628 * @return the program version string without the {@link ProgramVersionUtils#SNAPSHOT_VERSION}
629 * substring, if found, or the same <code>programVersionString</code> if not found.
630 * @since 1.3.0
631 */
632 private static String removeSnapshot(final String programVersionString) {
633 String programVersion = programVersionString;
634 final int snapshotIndex = programVersionString.indexOf(SNAPSHOT_VERSION);
635 if (snapshotIndex != MINUS_ONE_RETURN_CODE) {
636 programVersion = programVersionString.substring(0, snapshotIndex);
637 } else {
638 LOGGER.log(FINE, buildLogString(SNAPSHOT_VERSION_SPECIFIED_FINE, programVersionString));
639 }
640
641 return programVersion;
642 }
643
644 /**
645 * Private constructor to prevent from instantiation.
646 *
647 * @since 1.3.0
648 */
649 private ProgramVersionUtils() {
650 super();
651 }
652 }