View Javadoc
1   package org.codehaus.plexus.classworlds.launcher;
2   
3   /*
4    * Copyright 2001-2006 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.BufferedReader;
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileNotFoundException;
23  import java.io.FilenameFilter;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.InputStreamReader;
27  import java.net.MalformedURLException;
28  import java.net.URL;
29  import java.util.Properties;
30  
31  import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
32  import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
33  
34  /**
35   * Event based launcher configuration parser, delegating effective configuration handling to ConfigurationHandler.
36   *
37   * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
38   * @author Jason van Zyl
39   * @author Igor Fedorenko
40   * @see ConfigurationHandler
41   */
42  public class ConfigurationParser
43  {
44      public static final String MAIN_PREFIX = "main is";
45  
46      public static final String SET_PREFIX = "set";
47  
48      public static final String IMPORT_PREFIX = "import";
49  
50      public static final String LOAD_PREFIX = "load";
51  
52      /**
53       * Optionally spec prefix.
54       */
55      public static final String OPTIONALLY_PREFIX = "optionally";
56  
57      private ConfigurationHandler handler;
58  
59      private Properties systemProperties;
60  
61      public ConfigurationParser( ConfigurationHandler handler, Properties systemProperties )
62      {
63          this.handler = handler;
64          this.systemProperties = systemProperties;
65      }
66  
67      /**
68       * Parse launcher configuration file and send events to the handler.
69       */
70      public void parse( InputStream is )
71          throws IOException, ConfigurationException, DuplicateRealmException, NoSuchRealmException
72      {
73          BufferedReader reader = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );
74  
75          String line = null;
76  
77          int lineNo = 0;
78  
79          boolean mainSet = false;
80          
81          String curRealm = null;
82  
83          while ( true )
84          {
85              line = reader.readLine();
86  
87              if ( line == null )
88              {
89                  break;
90              }
91  
92              ++lineNo;
93              line = line.trim();
94  
95              if ( canIgnore( line ) )
96              {
97                  continue;
98              }
99  
100             if ( line.startsWith( MAIN_PREFIX ) )
101             {
102                 if ( mainSet )
103                 {
104                     throw new ConfigurationException( "Duplicate main configuration", lineNo, line );
105                 }
106 
107                 String conf = line.substring( MAIN_PREFIX.length() ).trim();
108 
109                 int fromLoc = conf.indexOf( "from" );
110 
111                 if ( fromLoc < 0 )
112                 {
113                     throw new ConfigurationException( "Missing from clause", lineNo, line );
114                 }
115 
116                 String mainClassName = filter( conf.substring( 0, fromLoc ).trim() );
117 
118                 String mainRealmName = filter( conf.substring( fromLoc + 4 ).trim() );
119 
120                 this.handler.setAppMain( mainClassName, mainRealmName );
121 
122                 mainSet = true;
123             }
124             else if ( line.startsWith( SET_PREFIX ) )
125             {
126                 String conf = line.substring( SET_PREFIX.length() ).trim();
127 
128                 int usingLoc = conf.indexOf( " using" ) + 1;
129 
130                 String property = null;
131 
132                 String propertiesFileName = null;
133 
134                 if ( usingLoc > 0 )
135                 {
136                     property = conf.substring( 0, usingLoc ).trim();
137 
138                     propertiesFileName = filter( conf.substring( usingLoc + 5 ).trim() );
139 
140                     conf = propertiesFileName;
141                 }
142 
143                 String defaultValue = null;
144 
145                 int defaultLoc = conf.indexOf( " default" ) + 1;
146 
147                 if ( defaultLoc > 0 )
148                 {
149                     defaultValue = filter( conf.substring( defaultLoc + 7 ).trim() );
150 
151                     if ( property == null )
152                     {
153                         property = conf.substring( 0, defaultLoc ).trim();
154                     }
155                     else
156                     {
157                         propertiesFileName = conf.substring( 0, defaultLoc ).trim();
158                     }
159                 }
160 
161                 String value = systemProperties.getProperty( property );
162 
163                 if ( value != null )
164                 {
165                     continue;
166                 }
167 
168                 if ( propertiesFileName != null )
169                 {
170                     File propertiesFile = new File( propertiesFileName );
171 
172                     if ( propertiesFile.exists() )
173                     {
174                         Properties properties = new Properties();
175 
176                         try
177                         {
178                             properties.load( new FileInputStream( propertiesFileName ) );
179 
180                             value = properties.getProperty( property );
181                         }
182                         catch ( Exception e )
183                         {
184                             // do nothing
185                         }
186                     }
187                 }
188 
189                 if ( value == null && defaultValue != null )
190                 {
191                     value = defaultValue;
192                 }
193 
194                 if ( value != null )
195                 {
196                     value = filter( value );
197                     systemProperties.setProperty( property, value );
198                 }
199             }
200             else if ( line.startsWith( "[" ) )
201             {
202                 int rbrack = line.indexOf( "]" );
203 
204                 if ( rbrack < 0 )
205                 {
206                     throw new ConfigurationException( "Invalid realm specifier", lineNo, line );
207                 }
208 
209                 String realmName = line.substring( 1, rbrack );
210 
211                 handler.addRealm( realmName );
212 
213                 curRealm = realmName;
214             }
215             else if ( line.startsWith( IMPORT_PREFIX ) )
216             {
217                 if ( curRealm == null )
218                 {
219                     throw new ConfigurationException( "Unhandled import", lineNo, line );
220                 }
221 
222                 String conf = line.substring( IMPORT_PREFIX.length() ).trim();
223 
224                 int fromLoc = conf.indexOf( "from" );
225 
226                 if ( fromLoc < 0 )
227                 {
228                     throw new ConfigurationException( "Missing from clause", lineNo, line );
229                 }
230 
231                 String importSpec = conf.substring( 0, fromLoc ).trim();
232 
233                 String relamName = conf.substring( fromLoc + 4 ).trim();
234 
235                 handler.addImportFrom( relamName, importSpec );
236 
237             }
238             else if ( line.startsWith( LOAD_PREFIX ) )
239             {
240                 String constituent = line.substring( LOAD_PREFIX.length() ).trim();
241 
242                 constituent = filter( constituent );
243 
244                 if ( constituent.indexOf( "*" ) >= 0 )
245                 {
246                     loadGlob( constituent, false /*not optionally*/ );
247                 }
248                 else
249                 {
250                     File file = new File( constituent );
251 
252                     if ( file.exists() )
253                     {
254                         handler.addLoadFile( file );
255                     }
256                     else
257                     {
258                         try
259                         {
260                           handler.addLoadURL( new URL( constituent ) );
261                         }
262                         catch ( MalformedURLException e )
263                         {
264                             throw new FileNotFoundException( constituent );
265                         }
266                     }
267                 }
268             }
269             else if ( line.startsWith( OPTIONALLY_PREFIX ) )
270             {
271                 String constituent = line.substring( OPTIONALLY_PREFIX.length() ).trim();
272 
273                 constituent = filter( constituent );
274 
275                 if ( constituent.indexOf( "*" ) >= 0 )
276                 {
277                     loadGlob( constituent, true /*optionally*/ );
278                 }
279                 else
280                 {
281                     File file = new File( constituent );
282 
283                     if ( file.exists() )
284                     {
285                         handler.addLoadFile( file );
286                     }
287                     else
288                     {
289                         try
290                         {
291                             handler.addLoadURL( new URL( constituent ) );
292                         }
293                         catch ( MalformedURLException e )
294                         {
295                             // swallow
296                         }
297                     }
298                 }
299             }
300             else
301             {
302                 throw new ConfigurationException( "Unhandled configuration", lineNo, line );
303             }
304         }
305 
306         reader.close();
307     }
308 
309     /**
310      * Load a glob into the specified classloader.
311      *
312      * @param line       The path configuration line.
313      * @param optionally Whether the path is optional or required
314      * @throws MalformedURLException If the line does not represent
315      *                               a valid path element.
316      * @throws FileNotFoundException If the line does not represent
317      *                               a valid path element in the filesystem.
318      * @throws ConfigurationException 
319      */
320     protected void loadGlob( String line,
321                              boolean optionally )
322         throws MalformedURLException, FileNotFoundException, ConfigurationException
323     {
324         File globFile = new File( line );
325 
326         File dir = globFile.getParentFile();
327         if ( !dir.exists() )
328         {
329             if ( optionally )
330             {
331                 return;
332             }
333             else
334             {
335                 throw new FileNotFoundException( dir.toString() );
336             }
337         }
338 
339         String localName = globFile.getName();
340 
341         int starLoc = localName.indexOf( "*" );
342 
343         final String prefix = localName.substring( 0, starLoc );
344 
345         final String suffix = localName.substring( starLoc + 1 );
346 
347         File[] matches = dir.listFiles( new FilenameFilter()
348         {
349             public boolean accept( File dir,
350                                    String name )
351             {
352                 if ( !name.startsWith( prefix ) )
353                 {
354                     return false;
355                 }
356 
357                 if ( !name.endsWith( suffix ) )
358                 {
359                     return false;
360                 }
361 
362                 return true;
363             }
364         } );
365 
366         for ( File match : matches )
367         {
368             handler.addLoadFile( match );
369         }
370     }
371 
372     /**
373      * Filter a string for system properties.
374      *
375      * @param text The text to filter.
376      * @return The filtered text.
377      * @throws ConfigurationException If the property does not
378      *                                exist or if there is a syntax error.
379      */
380     protected String filter( String text )
381         throws ConfigurationException
382     {
383         String result = "";
384 
385         int cur = 0;
386         int textLen = text.length();
387 
388         int propStart = -1;
389         int propStop = -1;
390 
391         String propName = null;
392         String propValue = null;
393 
394         while ( cur < textLen )
395         {
396             propStart = text.indexOf( "${", cur );
397 
398             if ( propStart < 0 )
399             {
400                 break;
401             }
402 
403             result += text.substring( cur, propStart );
404 
405             propStop = text.indexOf( "}", propStart );
406 
407             if ( propStop < 0 )
408             {
409                 throw new ConfigurationException( "Unterminated property: " + text.substring( propStart ) );
410             }
411 
412             propName = text.substring( propStart + 2, propStop );
413 
414             propValue = systemProperties.getProperty( propName );
415 
416             /* do our best if we are not running from surefire */
417             if ( propName.equals( "basedir" ) && ( propValue == null || propValue.equals( "" ) ) )
418             {
419                 propValue = ( new File( "" ) ).getAbsolutePath();
420 
421             }
422 
423             if ( propValue == null )
424             {
425                 throw new ConfigurationException( "No such property: " + propName );
426             }
427             result += propValue;
428 
429             cur = propStop + 1;
430         }
431 
432         result += text.substring( cur );
433 
434         return result;
435     }
436 
437     /**
438      * Determine if a line can be ignored because it is
439      * a comment or simply blank.
440      *
441      * @param line The line to test.
442      * @return <code>true</code> if the line is ignorable,
443      *         otherwise <code>false</code>.
444      */
445     private boolean canIgnore( String line )
446     {
447         return ( line.length() == 0 || line.startsWith( "#" ) );
448     }
449 }