| 1 | package atg.test; |
| 2 | |
| 3 | import java.io.File; |
| 4 | import java.io.IOException; |
| 5 | import java.lang.reflect.Method; |
| 6 | import java.sql.SQLException; |
| 7 | import java.util.ArrayList; |
| 8 | import java.util.Arrays; |
| 9 | import java.util.HashMap; |
| 10 | import java.util.Iterator; |
| 11 | import java.util.List; |
| 12 | import java.util.Map; |
| 13 | import java.util.Properties; |
| 14 | import java.util.Map.Entry; |
| 15 | |
| 16 | import junit.framework.TestCase; |
| 17 | |
| 18 | import org.apache.commons.io.FileUtils; |
| 19 | import org.apache.log4j.Logger; |
| 20 | |
| 21 | import atg.nucleus.GenericService; |
| 22 | import atg.nucleus.Nucleus; |
| 23 | import atg.nucleus.logging.ClassLoggingFactory; |
| 24 | import atg.nucleus.logging.ConsoleLogListener; |
| 25 | import atg.test.configuration.BasicConfiguration; |
| 26 | import atg.test.configuration.RepositoryConfiguration; |
| 27 | import atg.test.util.FileUtil; |
| 28 | import atg.test.util.RepositoryManager; |
| 29 | |
| 30 | /** |
| 31 | * Replacement base class for {@link AtgDustTestCase}. Extend this class and use |
| 32 | * the following 'pattern' whenever you want to junit test some atg components: |
| 33 | * <ul> |
| 34 | * <li><b>Copy</b> all needed configuration and repository mapping files to a |
| 35 | * staging location outside of your source tree using<b> |
| 36 | * {@link AtgDustCase#copyConfigurationFiles(String[], String, String...)}</b>. |
| 37 | * The staging directory will automatically be used as the configuration |
| 38 | * directory. Copying all needed priorities to a location outside of the source |
| 39 | * tree is the preferred method, because this frameworks creates properties on |
| 40 | * the fly and that could pollute your current source tree.</li> |
| 41 | * <!-- |
| 42 | * <li><b> |
| 43 | * |
| 44 | * <i>Or: </i></b>tell {@link AtgDustCase} class where the configuration |
| 45 | * location is by using <b>{@link AtgDustCase#setConfigurationLocation(String)} |
| 46 | * </b>, but be aware that the location will also be used for properties file |
| 47 | * generation.</li> |
| 48 | * --> |
| 49 | * </ul> |
| 50 | * |
| 51 | * <!-- p> <b>Rule of thumb:</b> When running repository tests, copy everything |
| 52 | * outside of your source tree (or when you use maven, use the target directory |
| 53 | * ). If you run basic component/formhandler tests, pointing it to your existing |
| 54 | * configuration directory might be sufficient. |
| 55 | * |
| 56 | * </p--> |
| 57 | * |
| 58 | * Repository based tests are depended on one of the two steps previously |
| 59 | * described plus: |
| 60 | * <ul> |
| 61 | * <li><b>{@link AtgDustCase#prepareRepository(String, String...)}</b> for |
| 62 | * testing against an default in-memory hsql database or <b> |
| 63 | * {@link AtgDustCase#prepareRepository(String, Properties, boolean, String...)} |
| 64 | * </b> for testing against an existing database.</li> |
| 65 | * </ul> |
| 66 | * |
| 67 | * If you need to generate some components "on the fly": |
| 68 | * <ul> |
| 69 | * <li><b>{@link AtgDustCase#createPropertyFile(String, String, Class)}</b></li> |
| 70 | * </ul> |
| 71 | * |
| 72 | * <p> |
| 73 | * Example usage can be found in test.SongsRepositoryTest. |
| 74 | * </p> |
| 75 | * |
| 76 | * <p> |
| 77 | * This class overrides Junit 3 and not Junit 4 because currently Junit 4 has |
| 78 | * some test runner/eclipse related bugs which makes it impossible for me to use |
| 79 | * it. |
| 80 | * </p> |
| 81 | * |
| 82 | * @author robert |
| 83 | */ |
| 84 | @SuppressWarnings("unchecked") |
| 85 | public class AtgDustCase extends TestCase { |
| 86 | |
| 87 | private static final Logger log = Logger.getLogger(AtgDustCase.class); |
| 88 | private RepositoryManager repositoryManager = new RepositoryManager(); |
| 89 | private final BasicConfiguration basicConfiguration = new BasicConfiguration(); |
| 90 | private File configurationLocation; |
| 91 | private Nucleus nucleus; |
| 92 | private boolean isDebug; |
| 93 | private String atgConfigPath; |
| 94 | private String environment; |
| 95 | private String localConfig; |
| 96 | private List<String> configDstsDir; |
| 97 | private static Map<String, Long> CONFIG_FILES_TIMESTAMPS, |
| 98 | CONFIG_FILES_GLOBAL_FORCE = null; |
| 99 | private static Class<?> perflib; |
| 100 | |
| 101 | public static final File TIMESTAMP_SER = new File(System |
| 102 | .getProperty("java.io.tmpdir") |
| 103 | + File.separator + "atg-dust-tstamp-rh.ser"), |
| 104 | GLOBAL_FORCE_SER = new File(System.getProperty("java.io.tmpdir") |
| 105 | + File.separator + "atg-dust-gforce-rh.ser"); |
| 106 | private static long SERIAL_TTL = 43200000L; |
| 107 | |
| 108 | /** |
| 109 | * Every *.properties file copied using this method will have it's scope (if |
| 110 | * one is available) set to global. |
| 111 | * |
| 112 | * @param srcDirs |
| 113 | * One or more directories containing needed configuration files. |
| 114 | * @param dstDir |
| 115 | * where to copy the above files to. This will also be the |
| 116 | * configuration location. |
| 117 | * @param excludes |
| 118 | * One or more directories not to include during the copy |
| 119 | * process. Use this one to speeds up the test cycle |
| 120 | * considerably. You can also call it with an empty |
| 121 | * {@link String[]} or <code>null</code> if nothing should be |
| 122 | * excluded |
| 123 | * @throws IOException |
| 124 | * Whenever some file related error's occur. |
| 125 | */ |
| 126 | protected final void copyConfigurationFiles(final String[] srcDirs, |
| 127 | final String dstDir, final String... excludes) throws IOException { |
| 128 | |
| 129 | setConfigurationLocation(dstDir); |
| 130 | |
| 131 | if (log.isDebugEnabled()) { |
| 132 | log.debug("Copying configuration files and " |
| 133 | + "forcing global scope on all configs"); |
| 134 | } |
| 135 | preCopyingOfConfigurationFiles(srcDirs, excludes); |
| 136 | |
| 137 | for (final String srcs : srcDirs) { |
| 138 | FileUtil.copyDirectory(srcs, dstDir, Arrays |
| 139 | .asList(excludes == null ? new String[] {} : excludes)); |
| 140 | } |
| 141 | |
| 142 | forceGlobalScopeOnAllConfigs(dstDir); |
| 143 | |
| 144 | if (FileUtil.isDirty()) { |
| 145 | FileUtil.serialize(GLOBAL_FORCE_SER, FileUtil |
| 146 | .getConfigFilesTimestamps()); |
| 147 | } |
| 148 | |
| 149 | } |
| 150 | |
| 151 | /** |
| 152 | * Donated by Remi Dupuis |
| 153 | * |
| 154 | * @param properties |
| 155 | * @throws IOException |
| 156 | */ |
| 157 | protected final void manageConfigurationFiles(Properties properties) |
| 158 | throws IOException { |
| 159 | |
| 160 | String atgConfigPath = properties.getProperty("atgConfigsJars") |
| 161 | .replace("/", File.separator); |
| 162 | String[] configs = properties.getProperty("configs").split(","); |
| 163 | String environment = properties.getProperty("environment"); |
| 164 | String localConfig = properties.getProperty("localConfig"); |
| 165 | String[] excludes = properties.getProperty("excludes").split(","); |
| 166 | String rootConfigDir = properties.getProperty("rootConfigDir").replace( |
| 167 | "/", File.separator); |
| 168 | int i = 0; |
| 169 | for (String conf : configs) { |
| 170 | String src = conf.split(" to ")[0]; |
| 171 | String dst = conf.split(" to ")[1]; |
| 172 | configs[i] = (rootConfigDir + "/" + src.trim() + " to " |
| 173 | + rootConfigDir + "/" + dst.trim()).replace("/", |
| 174 | File.separator); |
| 175 | i++; |
| 176 | } |
| 177 | i = 0; |
| 178 | for (String dir : excludes) { |
| 179 | excludes[i] = dir.trim(); |
| 180 | i++; |
| 181 | } |
| 182 | final List<String> srcsAsList = new ArrayList<String>(); |
| 183 | final List<String> distsAsList = new ArrayList<String>(); |
| 184 | |
| 185 | for (String config : configs) { |
| 186 | srcsAsList.add(config.split(" to ")[0]); |
| 187 | distsAsList.add(config.split(" to ")[1]); |
| 188 | } |
| 189 | |
| 190 | this.atgConfigPath = atgConfigPath; |
| 191 | this.environment = environment; |
| 192 | this.localConfig = localConfig; |
| 193 | // The Last dstdir is used for Configuration location |
| 194 | setConfigurationLocation(distsAsList.get(distsAsList.size() - 1)); |
| 195 | |
| 196 | if (log.isDebugEnabled()) { |
| 197 | log.debug("Copying configuration files and " |
| 198 | + "forcing global scope on all configs"); |
| 199 | } |
| 200 | preCopyingOfConfigurationFiles(srcsAsList.toArray(new String[] {}), |
| 201 | excludes); |
| 202 | |
| 203 | log.info("Copying configuration files and " |
| 204 | + "forcing global scope on all configs"); |
| 205 | // copy all files to it's destination |
| 206 | for (String config : configs) { |
| 207 | FileUtil.copyDirectory(config.split(" to ")[0], config |
| 208 | .split(" to ")[1], Arrays |
| 209 | .asList(excludes == null ? new String[] {} : excludes)); |
| 210 | log.debug(config); |
| 211 | log.debug(config.split(" to ")[0]); |
| 212 | log.debug(config.split(" to ")[1]); |
| 213 | } |
| 214 | |
| 215 | // forcing global scope on all configurations |
| 216 | for (String config : configs) { |
| 217 | String dstDir = config.split(" to ")[1]; |
| 218 | // forcing global scope on all property files |
| 219 | forceGlobalScopeOnAllConfigs(dstDir); |
| 220 | } |
| 221 | this.configDstsDir = distsAsList; |
| 222 | |
| 223 | } |
| 224 | |
| 225 | /** |
| 226 | * @param configurationStagingLocation |
| 227 | * The location where the property file should be created. This |
| 228 | * will also set the {@link AtgDustCase#configurationLocation}. |
| 229 | * |
| 230 | * @param nucleusComponentPath |
| 231 | * Nucleus component path (e.g /Some/Service/Impl). |
| 232 | * |
| 233 | * @param clazz |
| 234 | * The {@link Class} implementing the nucleus component specified |
| 235 | * in previous argument. |
| 236 | * |
| 237 | * @throws IOException |
| 238 | * If we have some File related errors |
| 239 | */ |
| 240 | protected final void createPropertyFile( |
| 241 | final String configurationStagingLocation, |
| 242 | final String nucleusComponentPath, final Class<?> clazz) |
| 243 | throws IOException { |
| 244 | this.configurationLocation = new File(configurationStagingLocation); |
| 245 | FileUtil.createPropertyFile(nucleusComponentPath, |
| 246 | configurationLocation, clazz.getClass(), |
| 247 | new HashMap<String, String>()); |
| 248 | } |
| 249 | |
| 250 | /** |
| 251 | * Prepares a test against an default in-memory hsql database. |
| 252 | * |
| 253 | * @param repoPath |
| 254 | * the nucleus component path of the repository to be tested. |
| 255 | * |
| 256 | * @param definitionFiles |
| 257 | * one or more repository definition files. |
| 258 | * @throws IOException |
| 259 | * The moment we have some properties/configuration related |
| 260 | * error |
| 261 | * @throws SQLException |
| 262 | * Whenever there is a database related error |
| 263 | * |
| 264 | */ |
| 265 | protected final void prepareRepository(final String repoPath, |
| 266 | final String... definitionFiles) throws SQLException, IOException { |
| 267 | |
| 268 | final Properties properties = new Properties(); |
| 269 | properties.put("driver", "org.hsqldb.jdbcDriver"); |
| 270 | properties.put("url", "jdbc:hsqldb:mem:testDb"); |
| 271 | properties.put("user", "sa"); |
| 272 | properties.put("password", ""); |
| 273 | |
| 274 | prepareRepository(repoPath, properties, true, true, definitionFiles); |
| 275 | |
| 276 | } |
| 277 | |
| 278 | /** |
| 279 | * Prepares a test against an existing database. |
| 280 | * |
| 281 | * @param repositoryPath |
| 282 | * The the repository to be tested, specified as nucleus |
| 283 | * component path. |
| 284 | * @param connectionProperties |
| 285 | * A {@link Properties} instance with the following values (in |
| 286 | * this example the properties are geared towards an mysql |
| 287 | * database): |
| 288 | * |
| 289 | * <pre> |
| 290 | * final Properties properties = new Properties(); |
| 291 | * properties.put("driver", "com.mysql.jdbc.Driver"); |
| 292 | * properties.put("url", "jdbc:mysql://localhost:3306/someDb"); |
| 293 | * properties.put("user", "someUserName"); |
| 294 | * properties.put("password", "somePassword"); |
| 295 | * </pre> |
| 296 | * |
| 297 | * |
| 298 | * @param dropTables |
| 299 | * If <code>true</code> then existing tables will be dropped and |
| 300 | * re-created, if set to <code>false</code> the existing tables |
| 301 | * will be used. |
| 302 | * |
| 303 | * @param createTables |
| 304 | * if set to <code>true</code> all non existing tables needed for |
| 305 | * the current test run will be created, if set to |
| 306 | * <code>false</code> this class expects all needed tables for |
| 307 | * this test run to be already created |
| 308 | * |
| 309 | * @param definitionFiles |
| 310 | * One or more needed repository definition files. |
| 311 | * @throws IOException |
| 312 | * The moment we have some properties/configuration related |
| 313 | * error |
| 314 | * @throws SQLException |
| 315 | * Whenever there is a database related error |
| 316 | * |
| 317 | */ |
| 318 | protected final void prepareRepository(final String repositoryPath, |
| 319 | final Properties connectionProperties, final boolean dropTables, |
| 320 | final boolean createTables, final String... definitionFiles) |
| 321 | throws SQLException, IOException { |
| 322 | |
| 323 | final Map<String, String> connectionSettings = new HashMap<String, String>(); |
| 324 | |
| 325 | for (final Iterator<Entry<Object, Object>> it = connectionProperties |
| 326 | .entrySet().iterator(); it.hasNext();) { |
| 327 | final Entry<Object, Object> entry = it.next(); |
| 328 | connectionSettings.put((String) entry.getKey(), (String) entry |
| 329 | .getValue()); |
| 330 | |
| 331 | } |
| 332 | final RepositoryConfiguration repositoryConfiguration = new RepositoryConfiguration(); |
| 333 | |
| 334 | repositoryConfiguration.setDebug(isDebug); |
| 335 | repositoryConfiguration |
| 336 | .createPropertiesByConfigurationLocation(configurationLocation); |
| 337 | repositoryConfiguration.createFakeXADataSource(configurationLocation, |
| 338 | connectionSettings); |
| 339 | repositoryConfiguration.createRepositoryConfiguration( |
| 340 | configurationLocation, repositoryPath, dropTables, |
| 341 | createTables, definitionFiles); |
| 342 | |
| 343 | repositoryManager.initializeMinimalRepositoryConfiguration( |
| 344 | configurationLocation, repositoryPath, connectionSettings, |
| 345 | dropTables, isDebug, definitionFiles); |
| 346 | } |
| 347 | |
| 348 | /** |
| 349 | * Method for retrieving a fully injected atg component |
| 350 | * |
| 351 | * @param nucleusComponentPath |
| 352 | * Path to a nucleus component (e.g. /Some/Service/Impl). |
| 353 | * @return Fully injected instance of the component registered under |
| 354 | * previous argument or <code>null</code> if there is an error. |
| 355 | * @throws IOException |
| 356 | */ |
| 357 | protected Object resolveNucleusComponent(final String nucleusComponentPath) |
| 358 | throws IOException { |
| 359 | startNucleus(configurationLocation); |
| 360 | return enableLoggingOnGenericService(nucleus |
| 361 | .resolveName(nucleusComponentPath)); |
| 362 | } |
| 363 | |
| 364 | /** |
| 365 | * Call this method to set the configuration location. |
| 366 | * |
| 367 | * @param configurationLocation |
| 368 | * The configuration location to set. Most of the time this |
| 369 | * location is a directory containing all repository definition |
| 370 | * files and component property files which are needed for the |
| 371 | * test. |
| 372 | */ |
| 373 | protected final void setConfigurationLocation( |
| 374 | final String configurationLocation) { |
| 375 | this.configurationLocation = new File(configurationLocation); |
| 376 | if (log.isDebugEnabled()) { |
| 377 | log.debug("Using configuration location: " |
| 378 | + this.configurationLocation.getPath()); |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | /** |
| 383 | * Always make sure to call this because it will do necessary clean up |
| 384 | * actions (shutting down in-memory database (if it was used) and the |
| 385 | * nucleus) so he next test can run safely. |
| 386 | */ |
| 387 | @Override |
| 388 | protected void tearDown() throws Exception { |
| 389 | super.tearDown(); |
| 390 | if (repositoryManager != null) { |
| 391 | repositoryManager.shutdownInMemoryDbAndCloseConnections(); |
| 392 | } |
| 393 | if (nucleus != null) { |
| 394 | nucleus.doStopService(); |
| 395 | nucleus.stopService(); |
| 396 | nucleus.destroy(); |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | /** |
| 401 | * Enables or disables the debug level of nucleus components. |
| 402 | * |
| 403 | * @param isDebug |
| 404 | * Setting this to <code>true</code> will enable debug on all |
| 405 | * (currently only on repository related) components, setting it |
| 406 | * to <code>false</code> turn's the debug off again. |
| 407 | */ |
| 408 | protected void setDebug(boolean isDebug) { |
| 409 | this.isDebug = isDebug; |
| 410 | } |
| 411 | |
| 412 | /** |
| 413 | * |
| 414 | * @param configpath |
| 415 | * @return |
| 416 | * @throws IOException |
| 417 | */ |
| 418 | private void startNucleus(final File configpath) throws IOException { |
| 419 | if (nucleus == null || !nucleus.isRunning()) { |
| 420 | ClassLoggingFactory.getFactory(); |
| 421 | basicConfiguration.setDebug(isDebug); |
| 422 | basicConfiguration |
| 423 | .createPropertiesByConfigurationLocation(configpath); |
| 424 | System.setProperty("atg.dynamo.license.read", "true"); |
| 425 | System.setProperty("atg.license.read", "true"); |
| 426 | // TODO: Can I safely keep this one disabled? |
| 427 | // NucleusServlet.addNamingFactoriesAndProtocolHandlers(); |
| 428 | |
| 429 | if (environment != null && !environment.equals("")) { |
| 430 | for (String property : environment.split(";")) { |
| 431 | String[] keyvalue = property.split("="); |
| 432 | System.setProperty(keyvalue[0], keyvalue[1]); |
| 433 | log.info(keyvalue[0] + "=" + keyvalue[1]); |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | String fullConfigPath = ""; |
| 438 | if (atgConfigPath != null && !atgConfigPath.equals("")) { |
| 439 | fullConfigPath = atgConfigPath + ";" + fullConfigPath; |
| 440 | } |
| 441 | if (configDstsDir != null && configDstsDir.size() > 0) { |
| 442 | for (String dst : configDstsDir) { |
| 443 | fullConfigPath = fullConfigPath + dst + ";"; |
| 444 | } |
| 445 | } else |
| 446 | fullConfigPath = configpath.getAbsolutePath(); |
| 447 | if (atgConfigPath != null && !atgConfigPath.equals("")) |
| 448 | fullConfigPath = fullConfigPath |
| 449 | + localConfig.replace("/", File.separator); |
| 450 | |
| 451 | log.info("The full config path used to start nucleus: " |
| 452 | + fullConfigPath); |
| 453 | System.setProperty("atg.configpath", new File(fullConfigPath) |
| 454 | .getAbsolutePath()); |
| 455 | nucleus = Nucleus.startNucleus(new String[] { fullConfigPath }); |
| 456 | |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | /** |
| 461 | * Will enable logging on the object/service that was passed in (as a method |
| 462 | * argument) if it's an instance of {@link GenericService}. This method is |
| 463 | * automatically called from |
| 464 | * {@link AtgDustCase#resolveNucleusComponent(String)}. Debug level is |
| 465 | * enabled the moment {@link AtgDustCase#setDebug(boolean)} was called with |
| 466 | * <code>true</code>. |
| 467 | * |
| 468 | * @param service |
| 469 | * an instance of GenericService |
| 470 | * |
| 471 | * @return the GenericService instance that was passed in with all log |
| 472 | * levels enabled, if it's a {@link GenericService} |
| 473 | */ |
| 474 | private Object enableLoggingOnGenericService(final Object service) { |
| 475 | if (service instanceof GenericService) { |
| 476 | ((GenericService) service).setLoggingDebug(isDebug); |
| 477 | ((GenericService) service).setLoggingInfo(true); |
| 478 | ((GenericService) service).setLoggingWarning(true); |
| 479 | ((GenericService) service).setLoggingError(true); |
| 480 | ((GenericService) service) |
| 481 | .removeLogListener(new ConsoleLogListener()); |
| 482 | ((GenericService) service).addLogListener(new ConsoleLogListener()); |
| 483 | } |
| 484 | return service; |
| 485 | } |
| 486 | |
| 487 | private void preCopyingOfConfigurationFiles(final String[] srcDirs, |
| 488 | final String excludes[]) throws IOException { |
| 489 | boolean isDirty = false; |
| 490 | for (final String src : srcDirs) { |
| 491 | for (final File file : (List<File>) FileUtils.listFiles(new File( |
| 492 | src), null, true)) { |
| 493 | if (!Arrays.asList( |
| 494 | excludes == null ? new String[] {} : excludes) |
| 495 | .contains(file.getName()) |
| 496 | && !file.getPath().contains(".svn") && file.isFile()) { |
| 497 | if (CONFIG_FILES_TIMESTAMPS.get(file.getPath()) != null |
| 498 | && file.lastModified() == CONFIG_FILES_TIMESTAMPS |
| 499 | .get(file.getPath())) { |
| 500 | } else { |
| 501 | CONFIG_FILES_TIMESTAMPS.put(file.getPath(), file |
| 502 | .lastModified()); |
| 503 | isDirty = true; |
| 504 | } |
| 505 | } |
| 506 | } |
| 507 | } |
| 508 | if (isDirty) { |
| 509 | if (log.isDebugEnabled()) { |
| 510 | log |
| 511 | .debug("Config files timestamps map is dirty an will be re serialized"); |
| 512 | } |
| 513 | |
| 514 | FileUtil.serialize(TIMESTAMP_SER, CONFIG_FILES_TIMESTAMPS); |
| 515 | } |
| 516 | |
| 517 | FileUtil.setConfigFilesTimestamps(CONFIG_FILES_TIMESTAMPS); |
| 518 | FileUtil.setConfigFilesGlobalForce(CONFIG_FILES_GLOBAL_FORCE); |
| 519 | } |
| 520 | |
| 521 | private void forceGlobalScopeOnAllConfigs(final String dstDir) |
| 522 | throws IOException { |
| 523 | if (perflib == null) { |
| 524 | for (final File file : (List<File>) FileUtils.listFiles(new File( |
| 525 | dstDir), new String[] { "properties" }, true)) { |
| 526 | new FileUtil().searchAndReplace("$scope=", "$scope=global\n", |
| 527 | file); |
| 528 | } |
| 529 | } else { |
| 530 | try { |
| 531 | List<File> payload = (List<File>) FileUtils.listFiles(new File( |
| 532 | dstDir), new String[] { "properties" }, true); |
| 533 | |
| 534 | Method schedule = perflib.getMethod("schedule", new Class[] { |
| 535 | int.class, List.class, Class.class, String.class, |
| 536 | Class[].class, List.class }); |
| 537 | |
| 538 | List<Object> list = new ArrayList<Object>(); |
| 539 | list.add("$scope="); |
| 540 | list.add("$scope=global\n"); |
| 541 | schedule.invoke(perflib.newInstance(), 4, payload, |
| 542 | FileUtil.class, "searchAndReplace", new Class[] { |
| 543 | String.class, String.class, File.class }, list); |
| 544 | } catch (Exception e) { |
| 545 | log.error("Error: ", e); |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | } |
| 550 | |
| 551 | static { |
| 552 | final String s = System.getProperty("SERIAL_TTL"); |
| 553 | if (log.isDebugEnabled()) { |
| 554 | log.debug(s == null ? "SERIAL_TTL has not been set " |
| 555 | + "using default value of: " + SERIAL_TTL |
| 556 | + " m/s or start VM with -DSERIAL_TTL=some_number_value" |
| 557 | : "SERIAL_TTL is set to:" + s); |
| 558 | } |
| 559 | try { |
| 560 | SERIAL_TTL = s != null ? Long.parseLong(s) * 1000 : SERIAL_TTL; |
| 561 | } catch (NumberFormatException e) { |
| 562 | log.error("Error using the -DSERIAL_TTL value: ", e); |
| 563 | } |
| 564 | CONFIG_FILES_TIMESTAMPS = FileUtil.deserialize(TIMESTAMP_SER, |
| 565 | SERIAL_TTL); |
| 566 | CONFIG_FILES_GLOBAL_FORCE = FileUtil.deserialize(GLOBAL_FORCE_SER, |
| 567 | SERIAL_TTL); |
| 568 | |
| 569 | try { |
| 570 | perflib = Class |
| 571 | .forName("com.bsdroot.util.concurrent.SchedulerService"); |
| 572 | } catch (ClassNotFoundException e) { |
| 573 | log |
| 574 | .debug("com.bsdroot.util.concurrent experimantal performance library not found, continuing normally"); |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | } |