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