View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2004-2005 Kevin Rogers
4   //
5   // This file is part of MillScript.
6   //
7   // MillScript is free software; you can redistribute it and/or modify it under
8   // the terms of the GNU General Public License as published by the Free
9   // Software Foundation; either version 2 of the License, or (at your option)
10  // any later version.
11  //
12  // MillScript is distributed in the hope that it will be useful, but WITHOUT
13  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  // more details.
16  //
17  // You should have received a copy of the GNU General Public License along with
18  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
19  // Place, Suite 330, Boston, MA  02111-1307  USA
20  ////////////////////////////////////////////////////////////////////////////////
21  package org.millscript.millscript.conf;
22  
23  import org.millscript.commons.alert.Alert;
24  import org.millscript.commons.alert.EscapeException;
25  import org.millscript.commons.alert.reporters.StandardMishapAlertReporter;
26  import org.millscript.commons.alert.reporters.StandardWarningAlertReporter;
27  import org.millscript.commons.util.EMap;
28  import org.millscript.commons.util.map.EHashMap;
29  import org.millscript.commons.vfs.VFS;
30  import org.millscript.commons.vfs.VFile;
31  import org.millscript.commons.vfs.VFolder;
32  import org.millscript.millscript.URLSource;
33  import org.millscript.millscript.alert.Alerts;
34  import org.millscript.millscript.conf.logging.Logger;
35  import org.millscript.millscript.functions.BinaryFunction;
36  import org.millscript.millscript.functions.DateFieldFunction;
37  import org.millscript.millscript.loaders.LoaderBuilder;
38  import org.millscript.millscript.tools.CastLibrary;
39  import org.millscript.millscript.tools.CharacterEntity;
40  import org.millscript.millscript.tools.XMLCharacterEntity;
41  import org.millscript.millscript.vm.Engine;
42  import org.millscript.millscript.vm.Package;
43  import org.millscript.millscript.vm.StandardEngine;
44  
45  import java.io.IOException;
46  import java.net.URL;
47  import java.nio.charset.Charset;
48  import java.util.Calendar;
49  import java.util.Enumeration;
50  
51  /**
52   * This class is a starting point for implementing a configuration object. You
53   * will still need to implement several methods, but basic properties and print
54   * methods are handled.
55   */
56  public abstract class AbstractConfiguration implements Configuration {
57  
58      /**
59       * Holds the VFS for this configuration.
60       */
61      protected final VFS vfs = new VFS();
62  
63      /**
64       * The current working direcotry.
65       */
66      protected final VFolder cwd = vfs.getCurrentWorkingFolder();
67  
68      /**
69       * Holds the HTML character entities configuration.
70       */
71      protected final CharacterEntity htmlCharacterEntities = new CharacterEntity();
72  
73      /**
74       * Holds the configured loaders for this MillScript configuration.
75       */
76      protected final LoaderBuilder loaderBuilder = new LoaderBuilder();
77  
78      /**
79       * Holds the logger for this MillScript configuration
80       */
81      protected Logger logger = null;
82  
83      /**
84       * The current output character set.
85       */
86      protected Charset outputCharset;
87  
88      /**
89       * Holds the basic properties defined in the configuration files.
90       */
91      protected final EMap< String, Object > properties = new EHashMap< String, Object >();
92  
93      /**
94       * Holds the XML character entities configuration.
95       */
96      protected final CharacterEntity xmlCharacterEntities = new XMLCharacterEntity();
97  
98      /**
99       * @see org.millscript.millscript.conf.Configuration#getBooleanProperty(java.lang.String)
100      */
101     public boolean getBooleanProperty( final String key ) {
102         if ( !properties.containsKey( key ) ) {
103             throw(
104                 Alerts.fault(
105                     "A required configuration property is not defined"
106                 ).culprit( "property", key ).mishap()
107             );
108         }
109         return CastLibrary.toBoolean( properties.get( key ) ).booleanValue();
110     }
111 
112     /**
113      * @see org.millscript.millscript.conf.Configuration#getCurrentWorkingFolder()
114      */
115     public final VFolder getCurrentWorkingFolder() {
116         return cwd;
117     }
118 
119     /**
120      * @see org.millscript.millscript.conf.Configuration#getHTMLCharacterEntity()
121      */
122     public CharacterEntity getHTMLCharacterEntity() {
123         return htmlCharacterEntities;
124     }
125 
126     /**
127      * @see org.millscript.millscript.conf.Configuration#getLoaderBuilder()
128      */
129     public LoaderBuilder getLoaderBuilder() {
130         return this.loaderBuilder;
131     }
132 
133     /**
134      * @see org.millscript.millscript.conf.Configuration#getLogger()
135      */
136     public Logger getLogger() {
137         return this.logger;
138     }
139 
140     /**
141      * @see org.millscript.millscript.conf.Configuration#getOutputCharset()
142      */
143     public Charset getOutputCharset() {
144         return this.outputCharset;
145     }
146 
147     /**
148      * @see org.millscript.millscript.conf.Configuration#getPackageConfFile(org.millscript.commons.vfs.VFolder)
149      */
150     public VFile getPackageConfFile( final VFolder packageDir ) {
151         return packageDir.getVFile( PACKAGE_CONF_FILE );
152     }
153 
154     /**
155      * @see org.millscript.millscript.conf.Configuration#getProperty(java.lang.String)
156      */
157     public String getProperty( final String key ) {
158         if ( !properties.containsKey( key ) ) {
159             throw(
160                 Alerts.fault(
161                     "A required configuration property is not defined"
162                 ).culprit( "property", key ).mishap()
163             );
164         }
165         return properties.get( key ).toString();
166     }
167 
168     /**
169      * @see org.millscript.millscript.conf.Configuration#getStandardEngine()
170      */
171     public Engine getStandardEngine() {
172         // Make the standard engine
173         final StandardEngine engine = new StandardEngine( this );
174         // Set the standard package for any new packages that are created
175         engine.setStandardPackage( this.getStandardPackage( engine ) );
176         // Add the standard package to the engine, so imports and pragmas can
177         // find it!
178         engine.addPackage( engine.getStandardPackage() );
179         // Return the new engine
180         return engine;
181     }
182 
183     /**
184      * @see org.millscript.millscript.conf.Configuration#getStandardPackage(org.millscript.millscript.vm.Engine)
185      */
186     public Package getStandardPackage( final Engine engine ) {
187         final Package standardPackage = new Package( engine, "millscript.standard", true );
188         // Add simple variables
189         standardPackage.bindProtectedConst( "absent", null );
190         standardPackage.bindProtectedConst( "false", Boolean.FALSE );
191         standardPackage.bindProtectedConst( "true", Boolean.TRUE );
192         // Add non-standard constructor functions
193         standardPackage.bindProtectedConst(
194             "dateDate",
195             new DateFieldFunction( Calendar.DATE, 0 )
196         );
197         standardPackage.bindProtectedConst(
198             "dateMonth", new DateFieldFunction( Calendar.MONTH, 1 )
199         );
200         standardPackage.bindProtectedConst(
201             "dateYear", new DateFieldFunction( Calendar.YEAR, 0 )
202         );
203         // Add the relational operation functions.
204         // TODO - These are only here temporarily, they will be handled like
205         // other standard functions in the next release
206         standardPackage.bindProtectedConst(
207             "<",
208             new BinaryFunction() {
209                 @Override
210                 @SuppressWarnings("unchecked")
211                 public Object apply2( final Object x, final Object y ) {
212                     return ((Comparable)x).compareTo( y ) < 0 ? Boolean.TRUE : Boolean.FALSE;
213                 }
214             }
215         );
216         standardPackage.bindProtectedConst(
217             "<=",
218             new BinaryFunction() {
219                 @Override
220                 @SuppressWarnings("unchecked")
221                 public Object apply2( final Object x, final Object y ) {
222                     return ((Comparable)x).compareTo( y ) <= 0 ? Boolean.TRUE : Boolean.FALSE;
223                 }
224             }
225         );
226         standardPackage.bindProtectedConst(
227             "=",
228             new BinaryFunction() {
229                 @Override
230                 public Object apply2( final Object x, final Object y ) {
231                     return (
232                         x == null ? ( y == null ? Boolean.TRUE : Boolean.FALSE ) :
233                         x.equals( y ) ? Boolean.TRUE : Boolean.FALSE
234                     );
235                 }
236             }
237         );
238         standardPackage.bindProtectedConst(
239             "/=",
240             new BinaryFunction() {
241                 @Override
242                 public Object apply2( final Object x, final Object y ) {
243                     return (
244                         x == null ? ( y == null ? Boolean.FALSE : Boolean.TRUE ) :
245                         x.equals( y ) ? Boolean.FALSE : Boolean.TRUE
246                     );
247                 }
248             }
249         );
250         standardPackage.bindProtectedConst(
251             "==",
252             new BinaryFunction() {
253                 @Override
254                 public Object apply2( final Object x, final Object y ) {
255                     return x == y ? Boolean.TRUE : Boolean.FALSE;
256                 }
257             }
258         );
259         standardPackage.bindProtectedConst(
260             "/==",
261             new BinaryFunction() {
262                 @Override
263                 public Object apply2( final Object x, final Object y ) {
264                     return x == y ? Boolean.FALSE : Boolean.TRUE;
265                 }
266             }
267         );
268         standardPackage.bindProtectedConst(
269             ">=",
270             new BinaryFunction() {
271                 @Override
272                 @SuppressWarnings("unchecked")
273                 public Object apply2( final Object x, final Object y ) {
274                     return ((Comparable)x).compareTo( y ) >= 0 ? Boolean.TRUE : Boolean.FALSE;
275                 }
276             }
277         );
278         standardPackage.bindProtectedConst(
279             ">",
280             new BinaryFunction() {
281                 @Override
282                 @SuppressWarnings("unchecked")
283                 public Object apply2( final Object x, final Object y ) {
284                     return ((Comparable)x).compareTo( y ) > 0 ? Boolean.TRUE : Boolean.FALSE;
285                 }
286             }
287         );
288         // Load the required configuration for the standard package
289         standardPackage.loadConf(
290             new URLSource(
291                 Configuration.class.getResource(
292                     "/org/millscript/millscript/conf/millscript.conf"
293                 )
294             )
295         );
296         standardPackage.loadConf(
297             new URLSource(
298                 Configuration.class.getResource(
299                     "/org/millscript/millscript/conf/loaders.conf"
300                 )
301             )
302         );
303         standardPackage.loadConf(
304             new URLSource(
305                 Configuration.class.getResource(
306                     "/org/millscript/millscript/conf/entities.conf"
307                 )
308             )
309         );
310         standardPackage.loadConf(
311             new URLSource(
312                 Configuration.class.getResource(
313                     "/org/millscript/millscript/conf/functions.conf"
314                 )
315             )
316         );
317         // Now scan for any plugins that are available.
318         try {
319             final Enumeration< URL > plugins = AbstractConfiguration.class.getClassLoader().getResources(
320                 "META-INF/millscript/conf/plugin.conf"
321             );
322             while ( plugins.hasMoreElements() ) {
323                 standardPackage.loadConf(
324                     new URLSource(
325                         plugins.nextElement()
326                     )
327                 );
328             }
329         } catch ( IOException ex ) {
330             throw Alerts.fault(
331                 "An unexpected error occurred while trying to load plugins"
332             ).setParentThrowable( ex ).mishap();
333         }
334         // Return the new package
335         return standardPackage;
336     }
337 
338     /**
339      * @see org.millscript.millscript.conf.Configuration#getVFS()
340      */
341     public VFS getVFS() {
342         return this.vfs;
343     }
344 
345     /**
346      * @see org.millscript.millscript.conf.Configuration#getXMLCharacterEntity()
347      */
348     public CharacterEntity getXMLCharacterEntity() {
349         return xmlCharacterEntities;
350     }
351 
352     /**
353      * @see org.millscript.millscript.conf.Configuration#reportAlertAsMishap(org.millscript.commons.alert.Alert)
354      */
355     public void reportAlertAsMishap( final Alert alert ) {
356         StandardMishapAlertReporter.MISHAP_REPORTER.report( alert );
357         if ( alert.getParentThrowable() != null ) {
358             this.getLogger().debugLine( "Trying to printStackTrace." );
359             this.getLogger().stackTrace( alert.getParentThrowable() );
360         }
361     }
362 
363     /**
364      * @see org.millscript.millscript.conf.Configuration#reportAlertAsWarning(org.millscript.commons.alert.Alert)
365      */
366     public void reportAlertAsWarning( final Alert alert ) {
367         StandardWarningAlertReporter.WARNING_REPORTER.report( alert );
368     }
369 
370     /**
371      * @see org.millscript.millscript.conf.Configuration#reportException(java.lang.Exception)
372      */
373     public void reportException( final Exception exception ) {
374         // Horrible.
375         if ( exception instanceof EscapeException ) {
376             this.reportAlertAsMishap(
377                 ((EscapeException) exception).getAlert()
378             );
379         } else if ( exception instanceof Alert ) {
380             this.reportAlertAsMishap( (Alert) exception );
381         } else {
382             this.getLogger().emerg( "Trapped : " );
383             String cname = exception.getClass().getName();
384             this.getLogger().emergLine( cname );
385             if ( exception.getMessage() != null ) {
386                 this.getLogger().emerg( "Message : " );
387                 this.getLogger().emergLine( exception.getMessage() );
388             }
389             this.getLogger().debugLine( "Trying to printStackTrace." );
390             this.getLogger().stackTrace( exception );
391         }
392     }
393 
394     /**
395      * @see org.millscript.millscript.conf.Configuration#setLogger(org.millscript.millscript.conf.logging.Logger)
396      */
397     public void setLogger( final Logger l ) {
398         this.logger = l;
399     }
400 
401     /**
402      * @see org.millscript.millscript.conf.Configuration#setOutputCharset(java.nio.charset.Charset)
403      */
404     public void setOutputCharset( final Charset cs ) {
405         this.outputCharset = cs;
406     }
407 
408     /**
409      * @see org.millscript.millscript.conf.Configuration#setProperty(java.lang.String, java.lang.Object)
410      */
411     public void setProperty( final String key, final Object value ) {
412         this.properties.insert( key, value );
413     }
414 
415 }