View Javadoc
1 /* ==================================================================== 2 * License: 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * 3. The end-user documentation included with the redistribution, 17 * if any, must include the following acknowledgment: 18 * "This product includes software developed by 19 * Robert Half International (http://www.rhi.com/)." 20 * Alternately, this acknowledgment may appear in the software itself, 21 * if and wherever such third-party acknowledgments normally appear. 22 * 23 * 4. The names "Parc", "RHI", and "Robert Half International" must 24 * not be used to endorse or promote products derived from this 25 * software without prior written permission. For written 26 * permission, please contact pete.mckinstry@rhi.com. 27 * 28 * 5. Products derived from this software may not be called "PARC", 29 * nor may "PARC" appear in their name, without prior written 30 * permission of Robert Half International. 31 * 32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 33 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 36 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 38 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 39 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 41 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 42 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * ==================================================================== 45 * 46 */ 47 package com.rhi.architecture.batch; 48 49 import com.rhi.architecture.lang.CompositeProperties; 50 import com.rhi.architecture.resource.InitializationException; 51 import com.rhi.architecture.resource.ResourceContext; 52 53 import java.io.IOException; 54 import java.io.InputStream; 55 import java.util.Properties; 56 57 /*** 58 * A BatchApplication adds audit and configuration capabilities 59 * to the standard application. It requires the following 60 * properties to be set: 61 * <br/> 62 * AuditAgent - This should be assigned to a 63 * concrete AuditAgent class that should be used to perform auditing of the 64 * batch process. ConfigMixin# - Any number of ConfigMixin's can be 65 * loaded by the BatchApplication. However they need to follow these guidelines: 66 * 1) implement the ConfigMixin interface, 2) be listed in the order required, 67 * where ConfigMixin0 is loaded first, and each increasing number is loaded in 68 * order until a number is missing at which point all Mixin's are assumed to be 69 * loaded, and the initialization process continues. 70 * 71 * @author Pete McKinstry 72 * @copyright 2002, Robert Half Int'l., Inc. All rights reserved. 73 * 74 * @since 1.0 75 */ 76 public abstract class BatchApplication extends AbstractApplication { 77 78 // property settings for this application. 79 private Properties resources; 80 // the audit agent to use 81 private AuditAgent auditAgent; 82 83 /*** 84 * default constructor 85 * 86 * @since 1.0 87 */ 88 public BatchApplication() { 89 resources = new CompositeProperties(); 90 } 91 92 /*** 93 * Return the audit agent to be used to perform audits. 94 * Note: this method is declared final because the audit 95 * agent is created dynamically based on a property file 96 * setting, thereby making it possible to override the 97 * type w/o modifying this method. (Also the reason that 98 * there is no setAuditAgent() method. 99 * 100 * @return AuditAgent concrete instance, potentially specific 101 * to this application. 102 * 103 * @since 1.0 104 */ 105 public final AuditAgent getAuditAgent() { 106 return auditAgent; 107 } 108 109 /*** 110 * Perform BatchApplication initialization. 111 * 1. Loads configuration information. 112 * a) command line arguments are loaded w/ property 113 * names of arg0, arg1, arg2, etc... 114 * 2. Initializes audit agent 115 * 3. Calls doInit() to allow sub-classes to perform 116 * any required initialization _after_ this method is 117 * complete. Note: sub-classes can override properties 118 * by loading an already existing property name. Last 119 * defined value wins. 120 * 121 * @param args the commandline arguments. usually used for configuration 122 * options. 123 * @throws InitializationException thrown when their is a problem configuring 124 * the application 125 * 126 * @since 1.0 127 */ 128 protected final void init(String args[]) 129 throws InitializationException { 130 try { 131 // 1. Bootstrap the application 132 // Checks for properties file & configMixin on the 133 // commandline. If found, loads them. Other mixins 134 // will be found & loaded after bootstrap. 135 bootstrap(args); 136 137 // 2. Mixin classes can be used to append configuration 138 // information from disparate sources w/o affecting the 139 // core batch architecture. This facility allows the 140 // interface developer to add any number of optional mixin 141 // classes. They will be loaded and initialized @ runtime 142 // prior to initializing any framework objects. 143 int count = 1; 144 while (true) { 145 // instead of using propertyNames() enumeration to find 146 // config mixins, i chose this method because it forces 147 // a certain well understood loading order. 148 String mixinClassName = 149 resources.getProperty("ConfigMixin" + count, "none"); 150 if (mixinClassName.equals("none")) { 151 break; 152 } 153 loadConfigMixin(mixinClassName); 154 count++; 155 } 156 157 // 3. Initialize the ResourceContext. 158 // so it's available to the audit agent. 159 ResourceContext ctx = new ResourceContext(); 160 ctx.init(resources); 161 162 if (isAuditEnabled()) { 163 // 4. create & initialize audit agent 164 String agentType = resources.getProperty("AuditAgent", 165 "com.rhi.architecture.batch.NullAuditAgent"); 166 auditAgent = AuditAgent.getInstance(agentType); 167 auditAgent.init(resources); 168 } 169 170 // 5. sub-classes get initialized last. 171 doInit(); 172 173 } 174 catch (NullPointerException npe) { 175 log().debug("null pointer exception while running init()."); 176 log().debug("probably config error."); 177 throw new InitializationException( 178 "null pointer exception in BatchApplication.init()", 179 npe); 180 } 181 182 } 183 184 /*** 185 * Bootstrap the application configuration. Normally this is 186 * done by loading the properties file autoSys passes via the 187 * commandline & then loading whatever data is found in the 188 * database referenced by those db connection properties. However 189 * many options exist for utilizing this startup logic. 190 * 1. If a properties file named <app-class-name>.properties 191 * exists, load it's name/value pairs. 192 * 2. Try loading System properties of 193 * a) bootstrap-mixin 194 * b) properties-file 195 * 3. Load commandline arguments. 196 * a) If -p|-properties-file found as commandline argument, 197 * assume the next argument is a properties filename 198 * that should override the System property. 199 * b) If -b|-bootstrap-mixin found as commandline argument, 200 * assume the next argument is a configMixin & load it 201 * accordingly. 202 * 4. If step 2 or 3 (3 overrides 2) found non-null values for 203 * either the bootstrap mixin or the properties filename, 204 * load them properties file first. 205 * 206 * @param args the commandline arguments. 207 * 208 * @exception InitializationException thrown if a problem is detected 209 * during the bootstrap process. 210 * 211 * @since 1.0 212 */ 213 private void bootstrap(String[] args) throws InitializationException { 214 215 // check for system properties 216 String propertiesFile = System.getProperty("properties-file", ""); 217 ; 218 String bootstrapMixin = System.getProperty("bootstrap-mixin", ""); 219 220 // load command line arguments 221 for (int i = 0; i < args.length; ++i) { 222 resources.setProperty("arg" + i, args[i]); 223 224 if ((args[i].equals("-p") == true) 225 || (args[i].equals("-properties-file") == true)) { 226 propertiesFile = args[i + 1]; 227 } 228 229 if ((args[i].equals("-b") == true) 230 || (args[i].equals("-bootstrap-mixin") == true)) { 231 bootstrapMixin = args[i + 1]; 232 } 233 } 234 // properties first. 235 if (propertiesFile.equals("") == false) { 236 loadProperties(propertiesFile); 237 } 238 else { 239 log().info("no bootstrap properties file found."); 240 } 241 // mixin can now take advantage of commandline properties. 242 if (bootstrapMixin.equals("") == false) { 243 loadConfigMixin(bootstrapMixin); 244 // for process based application, you should set the 245 // bootstrap configmixin so that it will be able to 246 // reload data correctly. 247 resources.setProperty("ConfigMixin0", bootstrapMixin); 248 } 249 else { 250 log().info("no bootstrap config mixin found."); 251 } 252 } 253 254 /*** 255 * Instantiate a Configuration Mixin class & load it's property 256 * settings. 257 * 258 * @param mixinClassName the class name of the mixin class to be used. 259 * @throws InitializationException thrown if a problem occurs loading a 260 * certain config mixin class. 261 * 262 * @since 1.0 263 */ 264 private void loadConfigMixin(String mixinClassName) 265 throws InitializationException { 266 try { 267 Class mixinClass = Class.forName(mixinClassName); 268 ConfigMixin config = (ConfigMixin) mixinClass.newInstance(); 269 config.loadConfiguration(resources); 270 } 271 catch (ClassNotFoundException cnfe) { 272 throw new InitializationException( 273 "ClassNotFoundException = " + cnfe.toString(), 274 cnfe); 275 } 276 catch (InstantiationException ie) { 277 throw new InitializationException( 278 "InstantiationException = " + ie.toString(), 279 ie); 280 } 281 catch (IllegalAccessException iae) { 282 throw new InitializationException( 283 "IllegalAccessException = " + iae.toString(), 284 iae); 285 } 286 } 287 288 /*** 289 * Load settings from property file. Called as part of initialization 290 * of the BatchApplication object. 291 * 292 * @param filename the properties file 293 * @throws InitializationException thrown if there is an error loading 294 * the properties. 295 * 296 * @since 1.0 297 */ 298 private void loadProperties(String filename) 299 throws InitializationException { 300 try { 301 // getClass() method returns the runtime type of the application 302 // class. We take advantage of this by loading the property 303 // setting according to the concrete classname thereby providing a 304 // unique name based on the real interface application class and 305 // removing the burden of configuration loading from the interface 306 // designer. 307 InputStream is = 308 getClass().getClassLoader().getResourceAsStream(filename); 309 if (is == null) { 310 log().error("<" + filename + "> not found."); 311 throw new InitializationException( 312 "config file missing = " + filename); 313 } 314 resources.load(is); 315 } 316 catch (IOException io) { 317 throw new InitializationException("IOException = " + io, io); 318 } 319 } 320 321 /*** 322 * Return the configuration information for this application as a 323 * Properties object. Sub-classes will use this method to retrieve 324 * the configuration information. 325 * 326 * @return Properties - the configuration data for this interface. 327 * 328 * @since 1.0 329 */ 330 protected Properties getProperties() { 331 return resources; 332 } 333 334 /*** 335 * Perform any cleanup required by the application framework. 336 * This method will also call the <code>doCleanup()</code> 337 * abstract method to allow concrete application classes to 338 * shutdown gracefully. 339 * 340 * @since 1.0 341 */ 342 public final void cleanup() { 343 // sub-classes get to cleanup resources first. 344 doCleanup(); 345 // cleanup this classes resources. 346 resources.clear(); 347 348 // shutdown any configured resources via ResourceContext. 349 ResourceContext ctx = new ResourceContext(); 350 ctx.cleanup(); 351 } 352 353 /*** 354 * The doInit() method is expected to be overriden by 355 * concrete application classes to perform any required 356 * initialization. 357 * 358 * @throws InitializationException thrown if a problem occuring in the init 359 * method of a sub-class. 360 * @since 1.0 361 */ 362 protected abstract void doInit() throws InitializationException; 363 364 /*** 365 * The doCleanup() method is expected to be overriden by 366 * concrete application classes to perform any required 367 * cleanup facilitating a graceful application shutdown. 368 * 369 * @since 1.0 370 */ 371 protected abstract void doCleanup(); 372 373 /*** 374 * returns true if the batch application should initialize the audit 375 * agent class. Otherwise returns false. To maintain backward 376 * compatibility, it always returns true unless overridden by a 377 * sub-class. 378 * 379 * @return boolean 380 * @since 2.0 381 */ 382 protected boolean isAuditEnabled() { 383 return true; 384 } 385 386 }

This page was automatically generated by Maven