View Javadoc
1 2 package com.werken.forehead; 3 4 /* 5 $Id: Forehead.java,v 1.1.1.1 2002/06/19 13:50:59 werken Exp $ 6 7 Copyright 2001 (C) The Werken Company. All Rights Reserved. 8 9 Redistribution and use of this software and associated documentation 10 ("Software"), with or without modification, are permitted provided 11 that the following conditions are met: 12 13 1. Redistributions of source code must retain copyright 14 statements and notices. Redistributions must also contain a 15 copy of this document. 16 17 2. Redistributions in binary form must reproduce the 18 above copyright notice, this list of conditions and the 19 following disclaimer in the documentation and/or other 20 materials provided with the distribution. 21 22 3. The name "Forehead" must not be used to endorse or promote 23 products derived from this Software without prior written 24 permission of The Werken Company. For written permission, 25 please contact bob@werken.com. 26 27 4. Products derived from this Software may not be called "Forehead" 28 nor may "Forehead" appear in their names without prior written 29 permission of The Werken Company. Forehead is a registered 30 trademark of The Werken Company. 31 32 5. Due credit should be given to the Forehead Project 33 (http://drools.org/). 34 35 THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS 36 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 37 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 38 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 39 THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 40 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 41 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 42 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46 OF THE POSSIBILITY OF SUCH DAMAGE. 47 48 */ 49 50 import java.io.File; 51 import java.io.FilenameFilter; 52 import java.io.FileInputStream; 53 import java.io.InputStream; 54 import java.io.InputStreamReader; 55 import java.io.BufferedReader; 56 import java.io.Reader; 57 import java.io.IOException; 58 import java.lang.reflect.Method; 59 import java.lang.reflect.Modifier; 60 import java.lang.reflect.InvocationTargetException; 61 import java.net.URL; 62 import java.net.MalformedURLException; 63 import java.util.HashMap; 64 import java.util.Map; 65 import java.util.Properties; 66 67 /*** ClassLoader configurator and application launcher. 68 * 69 * <p> 70 * This is the main command-line entry-point into the 71 * <code>forehead</code> framework. Please see 72 * the <code>forehead</code> documentation for usage 73 * instructions. 74 * </p> 75 * 76 * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a> 77 */ 78 public class Forehead 79 { 80 // ------------------------------------------------------------ 81 // Instance members 82 // ------------------------------------------------------------ 83 84 /*** ClassLoaders indexed by name. */ 85 private Map classLoaders; 86 87 /*** Root unnamed loader. */ 88 private ForeheadClassLoader rootLoader; 89 90 /*** The loader to use for entry-point lookup. */ 91 private ForeheadClassLoader entryLoader; 92 93 /*** The entry-point class. */ 94 private Class entryClass; 95 96 /*** The entry-point method. */ 97 private Method entryMethod; 98 99 // ------------------------------------------------------------ 100 // Constructors 101 // ------------------------------------------------------------ 102 103 /*** Construct. 104 */ 105 public Forehead() 106 { 107 this.classLoaders = new HashMap(); 108 } 109 110 // ------------------------------------------------------------ 111 // Instance methods 112 // ------------------------------------------------------------ 113 114 /*** Configure from an <code>InputStream</code>. 115 * 116 * @param in <code>InputStream</code> carrying configuration information. 117 * 118 * @throws ForeheadException If there is an error during configuration. 119 * @throws IOException If there is an error reading configuration information. 120 * @throws ClassNotFoundException If unable to locate entry-point class. 121 */ 122 public void config(InputStream in) throws ForeheadException, IOException, ClassNotFoundException 123 { 124 config( new BufferedReader( new InputStreamReader( in ) ) ); 125 } 126 127 /*** Configure from an <code>Reader</code>. 128 * 129 * @param in <code>Reader</code> carrying configuration information. 130 * 131 * @throws ForeheadException If there is an error during configuration. 132 * @throws IOException If there is an error reading configuration information. 133 * @throws ClassNotFoundException If unable to locate entry-point class. 134 */ 135 public void config(Reader in) throws ForeheadException, IOException, ClassNotFoundException 136 { 137 if ( in instanceof BufferedReader ) 138 { 139 config( in ); 140 } 141 else 142 { 143 config( new BufferedReader( in ) ); 144 } 145 } 146 147 /*** Configure from an <code>BufferedReader</code>. 148 * 149 * @param in <code>BufferedReader</code> carrying configuration information. 150 * 151 * @throws ForeheadException If there is an error during configuration. 152 * @throws IOException If there is an error reading configuration information. 153 * @throws ClassNotFoundException If unable to locate entry-point class. 154 */ 155 public void config(BufferedReader in) throws ForeheadException, IOException, ClassNotFoundException 156 { 157 this.rootLoader = new ForeheadClassLoader( getClass().getClassLoader(), 158 "$forehead-root$"); 159 160 String line = null; 161 162 ForeheadClassLoader currentLoader = this.rootLoader; 163 164 Properties props = new Properties(); 165 166 String entryLine = null; 167 168 while ( ( line = in.readLine() ) != null ) 169 { 170 line = line.trim(); 171 172 if ( "".equals( line ) ) 173 { 174 continue; 175 } 176 177 if ( line.startsWith( "#" ) ) 178 { 179 continue; 180 } 181 182 if ( line.startsWith( "+" ) ) 183 { 184 String propName = line.substring( 1 ); 185 String propValue = System.getProperty( propName ); 186 187 if ( propValue == null ) 188 { 189 throw new NoSuchPropertyException( propName ); 190 } 191 192 props.setProperty( propName, 193 propValue ); 194 195 continue; 196 } 197 198 if ( line.startsWith( "=" ) ) 199 { 200 entryLine = line; 201 continue; 202 } 203 204 ForeheadClassLoader parentLoader = null; 205 206 if ( line.startsWith( "[" ) 207 && 208 line.endsWith( "]" ) ) 209 { 210 String loaderName = line.substring( 1, 211 line.length() - 1 ); 212 213 int dotLoc = loaderName.lastIndexOf( "." ); 214 215 if ( dotLoc > 0 ) 216 { 217 String parentName = loaderName.substring( 0, 218 dotLoc ); 219 220 parentLoader = getClassLoader( parentName ); 221 222 if ( parentLoader == null ) 223 { 224 throw new NoSuchClassLoaderException( parentName ); 225 } 226 } 227 else 228 { 229 parentLoader = this.rootLoader; 230 } 231 232 currentLoader = createClassLoader( parentLoader, loaderName ); 233 } 234 else 235 { 236 String resolvedLine = resolveProperties( line, props ); 237 238 load( resolvedLine, 239 currentLoader ); 240 } 241 } 242 243 244 if ( entryLine == null ) 245 { 246 throw new NoEntryDescriptorException(); 247 } 248 249 setupEntry( entryLine ); 250 } 251 252 /*** Setup the entry-point. 253 * 254 * @param line The entry-point configuration line. 255 * 256 * @throws MalformedEntryDescriptorException If the entry-point descriptor is malformed. 257 * @throws NoSuchClassLoaderException If the entry-point descriptor references 258 * an unknown ClassLoader. 259 * @throws ClassNotFoundException If unable to locate the entry-point class. 260 */ 261 protected void setupEntry(String line) 262 throws MalformedEntryDescriptorException, NoSuchClassLoaderException, ClassNotFoundException 263 { 264 int leftBrackLoc = line.indexOf( "[" ); 265 266 if ( leftBrackLoc < 0 ) 267 { 268 throw new MalformedEntryDescriptorException( line ); 269 } 270 271 int rightBrackLoc = line.indexOf( "]", 272 leftBrackLoc + 1 ); 273 274 if ( rightBrackLoc < 0 ) 275 { 276 throw new MalformedEntryDescriptorException( line ); 277 } 278 279 String loaderName = line.substring( leftBrackLoc + 1, 280 rightBrackLoc ); 281 282 String className = line.substring( rightBrackLoc + 1 ).trim(); 283 284 this.entryLoader = getClassLoader( loaderName ); 285 286 if ( this.entryLoader == null ) 287 { 288 throw new NoSuchClassLoaderException( loaderName ); 289 } 290 291 this.entryClass = Class.forName( className, 292 true, 293 this.entryLoader ); 294 295 } 296 297 /*** Load a glob, file, or URL into the specified classloader. 298 * 299 * @param line The path configuration line. 300 * @param loader The loader to populate 301 * 302 * @throws MalformedURLException If the line does not represent 303 * a valid path element. 304 */ 305 protected void load(String line, 306 ForeheadClassLoader loader) throws MalformedURLException 307 { 308 if ( line.indexOf( "*" ) >= 0 ) 309 { 310 loadGlob( line, 311 loader ); 312 } 313 else 314 { 315 loadFileOrUrl( line, 316 loader ); 317 } 318 } 319 320 /*** Load a glob into the specified classloader. 321 * 322 * @param line The path configuration line. 323 * @param loader The loader to populate 324 * 325 * @throws MalformedURLException If the line does not represent 326 * a valid path element. 327 */ 328 protected void loadGlob(String line, 329 ForeheadClassLoader loader) throws MalformedURLException 330 { 331 File globFile = new File( line ); 332 333 File dir = globFile.getParentFile(); 334 335 String localName = globFile.getName(); 336 337 int starLoc = localName.indexOf( "*" ); 338 339 final String prefix = localName.substring( 0, 340 starLoc ); 341 342 final String suffix = localName.substring( starLoc + 1 ); 343 344 File[] matches = dir.listFiles( 345 new FilenameFilter() { 346 public boolean accept(File dir, String name) 347 { 348 if ( prefix != null 349 && 350 !name.startsWith( prefix ) ) 351 { 352 return false; 353 } 354 355 if ( suffix != null 356 && 357 !name.endsWith( suffix ) ) 358 { 359 return false; 360 } 361 362 return true; 363 } 364 } 365 ); 366 367 for ( int i = 0 ; i < matches.length ; ++i ) 368 { 369 loader.addURL( matches[i].toURL() ); 370 } 371 } 372 373 /*** Load a file or URL into the specified classloader. 374 * 375 * @param line The path configuration line. 376 * @param loader The loader to populate 377 * 378 * @throws MalformedURLException If the line does not represent 379 * a valid path element. 380 */ 381 protected void loadFileOrUrl(String line, 382 ForeheadClassLoader loader) throws MalformedURLException 383 { 384 URL url = null; 385 386 File file = new File( line ); 387 388 if ( file.exists() ) 389 { 390 url = file.toURL(); 391 } 392 else 393 { 394 url = new URL( line ); 395 } 396 397 loader.addURL( url ); 398 } 399 400 /*** Create a new ClassLoader given a parent and a name. 401 * 402 * @param parent The parent of the ClassLoader to create. 403 * @param name The name of the ClassLoader to create. 404 * 405 * @return A newly configured <code>ClassLoader</code>. 406 */ 407 protected ForeheadClassLoader createClassLoader(ForeheadClassLoader parent, 408 String name) 409 { 410 ForeheadClassLoader loader = new ForeheadClassLoader( parent, 411 name ); 412 413 this.classLoaders.put( name, 414 loader ); 415 416 return loader; 417 } 418 419 /*** Retrieve a ClassLoader by name. 420 * 421 * @param name The name of the ClassLoader to retrieve. 422 * 423 * @return The associated ClassLoader, or <code>null</code> 424 * if none. 425 */ 426 public ForeheadClassLoader getClassLoader(String name) 427 { 428 return (ForeheadClassLoader) this.classLoaders.get( name ); 429 } 430 431 /*** Resolve imported properties. 432 * 433 * @param input The string input to resolve properties. 434 * @param props Properties to resolve against. 435 * 436 * @return The string with properties resolved. 437 */ 438 public String resolveProperties(String input, 439 Properties props) 440 { 441 String output = ""; 442 443 int cur = 0; 444 445 int prefixLoc = 0; 446 int suffixLoc = 0; 447 448 while ( cur < input.length() ) 449 { 450 prefixLoc = input.indexOf( "${", 451 cur ); 452 453 if ( prefixLoc < 0 ) 454 { 455 //output = output + input.substring( cur ); 456 break; 457 } 458 459 suffixLoc = input.indexOf( "}", 460 prefixLoc ); 461 462 String propName = input.substring( prefixLoc + 2, 463 suffixLoc ); 464 465 output = output + input.substring( cur, prefixLoc ); 466 467 output = output + props.getProperty( propName ); 468 469 cur = suffixLoc + 1; 470 } 471 472 output = output + input.substring( cur ); 473 474 return output; 475 } 476 477 /*** Launch the wrapped application. 478 * 479 * @param args Command-line args to pass to wrapped application. 480 * 481 * @throws NoSuchEntryMethodException If unable to find the entry method on the class. 482 * @throws IllegalAccessException If an error occurs while attempting to invoke the 483 * entry-point method. 484 * @throws InvocationTargetException If an error occurs while attempting to invoke the 485 * entry-point method. 486 */ 487 public void run(String[] args) throws NoSuchEntryMethodException, IllegalAccessException, InvocationTargetException 488 { 489 Method[] methods = this.entryClass.getMethods(); 490 491 for ( int i = 0 ; i < methods.length ; ++i ) 492 { 493 if ( !"main".equals( methods[i].getName() ) ) 494 { 495 continue; 496 } 497 498 int modifiers = methods[i].getModifiers(); 499 500 if ( !( Modifier.isStatic( modifiers ) 501 && 502 Modifier.isPublic( modifiers ) ) ) 503 { 504 continue; 505 } 506 507 if ( methods[i].getReturnType() != Void.TYPE ) 508 { 509 continue; 510 } 511 512 Class[] paramTypes = methods[i].getParameterTypes(); 513 514 if ( paramTypes.length != 1 ) 515 { 516 continue; 517 } 518 519 if ( paramTypes[0] != String[].class ) 520 { 521 continue; 522 } 523 524 this.entryMethod = methods[i]; 525 break; 526 } 527 528 if ( this.entryMethod == null ) 529 { 530 throw new NoSuchEntryMethodException( this.entryClass, 531 "public static void main(String[] args)" ); 532 } 533 534 Thread.currentThread().setContextClassLoader( this.entryLoader ); 535 536 this.entryMethod.invoke( this.entryClass, 537 new Object[] { args } ); 538 } 539 540 // ------------------------------------------------------------ 541 // Class methods 542 // ------------------------------------------------------------ 543 544 /*** Main. 545 * 546 * @param args Command-line arguments to pass to the wrapped 547 * application. 548 */ 549 public static void main(String[] args) 550 { 551 String confFileName = System.getProperty( "forehead.conf.file" ); 552 553 File confFile = new File( confFileName ); 554 555 Forehead forehead = new Forehead(); 556 557 try 558 { 559 forehead.config( new FileInputStream( confFile ) ); 560 561 forehead.run( args ); 562 } 563 catch (NoSuchEntryMethodException e) 564 { 565 System.err.println( "No method on class " + e.getEntryClass() + " matching: " + e.getEntryMethodDescriptor() ); 566 e.printStackTrace(); 567 } 568 catch (ForeheadException e) 569 { 570 System.err.println( "Error during configuration: " + e.getLocalizedMessage() ); 571 e.printStackTrace(); 572 } 573 catch (MalformedURLException e) 574 { 575 e.printStackTrace(); 576 } 577 catch (IOException e) 578 { 579 System.err.println( "Error reading configuration: " + e.getLocalizedMessage() ); 580 e.printStackTrace(); 581 } 582 catch (ClassNotFoundException e) 583 { 584 System.err.println( e.getLocalizedMessage() ); 585 e.printStackTrace(); 586 } 587 catch (Exception e) 588 { 589 e.printStackTrace(); 590 } 591 } 592 }

This page was automatically generated by Maven