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 }