View Javadoc
1 package org.codehaus.classworlds; 2 3 /* 4 $Id: Configurator.java,v 1.2 2003/08/29 08:47:14 user57 Exp $ 5 6 Copyright 2002 (C) The Werken Company. All Rights Reserved. 7 8 Redistribution and use of this software and associated documentation 9 ("Software"), with or without modification, are permitted provided 10 that the following conditions are met: 11 12 1. Redistributions of source code must retain copyright 13 statements and notices. Redistributions must also contain a 14 copy of this document. 15 16 2. Redistributions in binary form must reproduce the 17 above copyright notice, this list of conditions and the 18 following disclaimer in the documentation and/or other 19 materials provided with the distribution. 20 21 3. The name "classworlds" must not be used to endorse or promote 22 products derived from this Software without prior written 23 permission of The Werken Company. For written permission, 24 please contact bob@werken.com. 25 26 4. Products derived from this Software may not be called "classworlds" 27 nor may "classworlds" appear in their names without prior written 28 permission of The Werken Company. "classworlds" is a registered 29 trademark of The Werken Company. 30 31 5. Due credit should be given to The Werken Company. 32 (http://classworlds.werken.com/). 33 34 THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS 35 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 36 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 37 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 38 THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 39 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 40 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 41 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 42 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 43 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 44 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 45 OF THE POSSIBILITY OF SUCH DAMAGE. 46 47 */ 48 49 import java.io.File; 50 import java.io.FilenameFilter; 51 import java.io.BufferedReader; 52 import java.io.InputStream; 53 import java.io.InputStreamReader; 54 import java.io.IOException; 55 import java.io.FileNotFoundException; 56 import java.net.URL; 57 import java.net.MalformedURLException; 58 import java.util.Map; 59 import java.util.HashMap; 60 import java.util.Iterator; 61 import java.util.Collections; 62 import java.util.Comparator; 63 64 import java.util.List; 65 import java.util.ArrayList; 66 67 /*** <code>Launcher</code> configurator. 68 * 69 * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a> 70 * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a> 71 * 72 * @version $Id: Configurator.java,v 1.2 2003/08/29 08:47:14 user57 Exp $ 73 */ 74 class Configurator 75 { 76 // ------------------------------------------------------------ 77 // Constants 78 // ------------------------------------------------------------ 79 80 /*** Main spec prefix. */ 81 public static final String MAIN_PREFIX = "main is"; 82 83 /*** Import spec prefix. */ 84 public static final String IMPORT_PREFIX = "import"; 85 86 /*** Load spec prefix. */ 87 public static final String LOAD_PREFIX = "load"; 88 89 // ------------------------------------------------------------ 90 // Instance members 91 // ------------------------------------------------------------ 92 93 /*** The launcher to configure. */ 94 private Launcher launcher; 95 96 /*** Processed Realms. */ 97 private Map configuredRealms; 98 99 // ------------------------------------------------------------ 100 // Constructors 101 // ------------------------------------------------------------ 102 103 /*** Construct. 104 * 105 * @param launcher The launcher to configure. 106 */ 107 Configurator(Launcher launcher) 108 { 109 this.launcher = launcher; 110 111 configuredRealms = new HashMap(); 112 } 113 114 // ------------------------------------------------------------ 115 // Instance methods 116 // ------------------------------------------------------------ 117 118 /*** Configure from a file. 119 * 120 * @param is The config input stream 121 * 122 * @throws IOException If an error occurs reading the config file. 123 * @throws MalformedURLException If the config file contains invalid URLs. 124 * @throws ConfigurationException If the config file is corrupt. 125 * @throws DuplicateRealmException If the config file defines two realms with the same id. 126 * @throws NoSuchRealmException If the config file defines a main entry point in 127 * a non-existent realm. 128 */ 129 void configure(InputStream is) 130 throws IOException, MalformedURLException, ConfigurationException, DuplicateRealmException, NoSuchRealmException 131 { 132 BufferedReader reader = new BufferedReader( new InputStreamReader( is ) ); 133 134 ClassWorld world = new ClassWorld(); 135 ClassRealm curRealm = null; 136 137 String line = null; 138 139 int lineNo = 0; 140 boolean mainSet = false; 141 142 while ( true ) 143 { 144 line = reader.readLine(); 145 146 if ( line == null ) 147 { 148 break; 149 } 150 151 ++lineNo; 152 line = line.trim(); 153 154 if ( canIgnore( line ) ) 155 { 156 continue; 157 } 158 159 if ( line.startsWith( MAIN_PREFIX ) ) 160 { 161 if ( mainSet ) 162 { 163 throw new ConfigurationException( "Duplicate main configuration", lineNo, line ); 164 } 165 166 String conf = line.substring( MAIN_PREFIX.length() ).trim(); 167 168 int fromLoc = conf.indexOf( "from" ); 169 if ( fromLoc < 0 ) 170 { 171 throw new ConfigurationException( "Missing from clause", lineNo, line ); 172 } 173 174 String mainClassName = conf.substring( 0, 175 fromLoc ).trim(); 176 177 String mainRealmName = conf.substring( fromLoc + 4 ).trim(); 178 179 this.launcher.setAppMain( mainClassName, 180 mainRealmName ); 181 182 mainSet = true; 183 } 184 else if ( line.startsWith( "[" ) ) 185 { 186 int rbrack = line.indexOf( "]" ); 187 188 if ( rbrack < 0 ) 189 { 190 throw new ConfigurationException( "Invalid realm specifier", lineNo, line ); 191 } 192 193 String realmName = line.substring( 1, 194 rbrack ); 195 196 curRealm = world.newRealm( realmName ); 197 198 // Stash the configured realm for subsequent association processing. 199 configuredRealms.put( realmName, curRealm ); 200 } 201 else if ( line.startsWith( IMPORT_PREFIX ) ) 202 { 203 if ( curRealm == null ) 204 { 205 throw new ConfigurationException( "Unhandled import", lineNo, line ); 206 } 207 208 String conf = line.substring( IMPORT_PREFIX.length() ).trim(); 209 210 int fromLoc = conf.indexOf( "from" ); 211 if ( fromLoc < 0 ) 212 { 213 throw new ConfigurationException( "Missing from clause", lineNo, line ); 214 } 215 216 String importSpec = conf.substring( 0, 217 fromLoc ).trim(); 218 219 String relamName = conf.substring( fromLoc + 4 ).trim(); 220 221 curRealm.importFrom( relamName, 222 importSpec ); 223 224 } 225 else if ( line.startsWith( LOAD_PREFIX ) ) 226 { 227 String constituent = line.substring( LOAD_PREFIX.length() ).trim(); 228 229 constituent = filter( constituent ); 230 231 if ( constituent.indexOf( "*" ) >= 0 ) 232 { 233 loadGlob( constituent, curRealm ); 234 } 235 else 236 { 237 File file = new File( constituent ); 238 239 if ( file.exists() ) 240 { 241 curRealm.addConstituent( file.toURL() ); 242 } 243 else 244 { 245 try 246 { 247 curRealm.addConstituent( new URL( constituent ) ); 248 } 249 catch (MalformedURLException e) 250 { 251 throw new FileNotFoundException( constituent ); 252 } 253 } 254 } 255 } 256 else 257 { 258 throw new ConfigurationException( "Unhandled configuration", lineNo, line ); 259 } 260 } 261 262 // Associate child realms to their parents. 263 associateRealms(); 264 265 this.launcher.setWorld( world ); 266 267 reader.close(); 268 } 269 270 /*** 271 * Associate parent realms with their children. 272 */ 273 protected void associateRealms() 274 { 275 List sortRealmNames = new ArrayList( configuredRealms.keySet() ); 276 277 // sort by name 278 Comparator comparator = new Comparator() 279 { 280 public int compare( Object o1, Object o2 ) 281 { 282 String g1 = (String) o1; 283 String g2 = (String) o2; 284 return g1.compareTo( g2 ); 285 } 286 }; 287 288 Collections.sort( sortRealmNames, comparator ); 289 290 // So now we have something like the following for defined 291 // realms: 292 // 293 // root 294 // root.maven 295 // root.maven.plugin 296 // 297 // Now if the name of a realm is a superset of an existing realm 298 // the we want to make child/parent associations. 299 300 for ( Iterator i = sortRealmNames.iterator(); i.hasNext(); ) 301 { 302 String realmName = (String) i.next(); 303 304 int j = realmName.lastIndexOf('.'); 305 306 if ( j > 0 ) 307 { 308 String parentRealmName = realmName.substring( 0, j ); 309 310 ClassRealm parentRealm = (ClassRealm) configuredRealms.get( parentRealmName ); 311 312 if ( parentRealm != null ) 313 { 314 ClassRealm realm = (ClassRealm) configuredRealms.get( realmName ); 315 realm.setParent( parentRealm ); 316 } 317 } 318 } 319 } 320 321 /*** Load a glob into the specified classloader. 322 * 323 * @param line The path configuration line. 324 * @param realm The realm to populate 325 * 326 * @throws MalformedURLException If the line does not represent 327 * a valid path element. 328 */ 329 protected void loadGlob(String line, 330 ClassRealm realm) throws MalformedURLException 331 { 332 File globFile = new File( line ); 333 334 File dir = globFile.getParentFile(); 335 336 String localName = globFile.getName(); 337 338 int starLoc = localName.indexOf( "*" ); 339 340 final String prefix = localName.substring( 0, 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 ( !name.startsWith( prefix ) ) 349 { 350 return false; 351 } 352 353 if ( !name.endsWith( suffix ) ) 354 { 355 return false; 356 } 357 358 return true; 359 } 360 } 361 ); 362 363 for ( int i = 0 ; i < matches.length ; ++i ) 364 { 365 realm.addConstituent( matches[i].toURL() ); 366 } 367 } 368 369 /*** Filter a string for system properties. 370 * 371 * @param text The text to filter. 372 * 373 * @return The filtered text. 374 * 375 * @throws ConfigurationException If the property does not 376 * exist or if there is a syntax error. 377 */ 378 protected String filter(String text) throws ConfigurationException 379 { 380 String result = ""; 381 382 int cur = 0; 383 int textLen = text.length(); 384 385 int propStart = -1; 386 int propStop = -1; 387 388 String propName = null; 389 String propValue = null; 390 391 while ( cur < textLen ) 392 { 393 propStart = text.indexOf( "${", 394 cur ); 395 396 if ( propStart < 0 ) 397 { 398 break; 399 } 400 401 result += text.substring(cur, 402 propStart ); 403 404 propStop = text.indexOf( "}", 405 propStart ); 406 407 if ( propStop < 0 ) 408 { 409 throw new ConfigurationException( "Unterminated property: " + text.substring( propStart ) ); 410 } 411 412 propName = text.substring( propStart + 2, 413 propStop ); 414 415 propValue = System.getProperty( propName ); 416 417 if ( propValue == null ) 418 { 419 throw new ConfigurationException( "No such property: " + propName ); 420 } 421 result += propValue; 422 423 cur = propStop + 1; 424 } 425 426 result += text.substring( cur ); 427 428 return result; 429 } 430 431 /*** Determine if a line can be ignored because it is 432 * a comment or simply blank. 433 * 434 * @param line The line to test. 435 * 436 * @return <code>true</code> if the line is ignorable, 437 * otherwise <code>false</code>. 438 */ 439 private boolean canIgnore(String line) 440 { 441 return ( line.length() == 0 442 || 443 line.startsWith( "#" ) ); 444 } 445 } 446

This page was automatically generated by Maven