001    /*
002     $Id: CompilerConfiguration.java 3906 2006-07-19 00:11:46Z glaforge $
003    
004     Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005    
006     Redistribution and use of this software and associated documentation
007     ("Software"), with or without modification, are permitted provided
008     that the following conditions are met:
009    
010     1. Redistributions of source code must retain copyright
011        statements and notices.  Redistributions must also contain a
012        copy of this document.
013    
014     2. Redistributions in binary form must reproduce the
015        above copyright notice, this list of conditions and the
016        following disclaimer in the documentation and/or other
017        materials provided with the distribution.
018    
019     3. The name "groovy" must not be used to endorse or promote
020        products derived from this Software without prior written
021        permission of The Codehaus.  For written permission,
022        please contact info@codehaus.org.
023    
024     4. Products derived from this Software may not be called "groovy"
025        nor may "groovy" appear in their names without prior written
026        permission of The Codehaus. "groovy" is a registered
027        trademark of The Codehaus.
028    
029     5. Due credit should be given to The Codehaus -
030        http://groovy.codehaus.org/
031    
032     THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033     ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034     NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035     FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
036     THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043     OF THE POSSIBILITY OF SUCH DAMAGE.
044    
045     */
046    
047    package org.codehaus.groovy.control;
048    
049    import org.codehaus.groovy.control.io.NullWriter;
050    import org.codehaus.groovy.control.messages.WarningMessage;
051    
052    import java.io.File;
053    import java.io.PrintWriter;
054    import java.util.LinkedList;
055    import java.util.List;
056    import java.util.Properties;
057    import java.util.StringTokenizer;
058    
059    
060    /**
061     * Compilation control flags and coordination stuff.
062     *
063     * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
064     * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
065     * @version $Id: CompilerConfiguration.java 3906 2006-07-19 00:11:46Z glaforge $
066     */
067    
068    public class CompilerConfiguration {
069        public static final CompilerConfiguration DEFAULT = new CompilerConfiguration();
070    
071        /** Whether to use the JSR parser or not if no property is explicitly stated */
072        protected static final boolean DEFAULT_JSR_FLAG = true;
073    
074        private static boolean jsrGroovy;
075    
076        /**
077         * See WarningMessage for levels
078         */
079        private int warningLevel;
080        /**
081         * Encoding for source files
082         */
083        private String sourceEncoding;
084        /**
085         * A PrintWriter for communicating with the user
086         */
087        private PrintWriter output;
088        /**
089         * Directory into which to write classes
090         */
091        private File targetDirectory;
092        /**
093         * Classpath for use during compilation
094         */
095        private LinkedList classpath;
096        /**
097         * If true, the compiler should produce action information
098         */
099        private boolean verbose;
100        /**
101         * If true, debugging code should be activated
102         */
103        private boolean debug;
104        /**
105         * The number of non-fatal errors to allow before bailing
106         */
107        private int tolerance;
108        /**
109         * Base class name for scripts (must derive from Script)
110         */
111        private String scriptBaseClass;
112        /**
113         * should we use the New JSR Groovy parser or stay with the static one
114         */
115        private boolean useNewGroovy = getDefaultJsrFlag();
116    
117        private ParserPluginFactory pluginFactory;
118    
119        /**
120         * extension used to find a groovy file
121         */
122        private String defaultScriptExtension = ".groovy";
123        
124        /**
125         * if set to true recompilation is enabled
126         */
127        private boolean recompileGroovySource;
128        
129        /**
130         * sets the minimum of time after a script can be recompiled.
131         */
132        private int minimumRecompilationInterval;
133    
134        /**
135         * Sets the Flags to defaults.
136         */
137        public CompilerConfiguration() {
138            //
139            // Set in safe defaults
140    
141            setWarningLevel(WarningMessage.LIKELY_ERRORS);
142            setSourceEncoding("US-ASCII");
143            setOutput(null);
144            setTargetDirectory((File) null);
145            setClasspath("");
146            setVerbose(false);
147            setDebug(false);
148            setTolerance(10);
149            setScriptBaseClass(null);
150            setRecompileGroovySource(false);
151            setMinimumRecompilationInterval(100);
152    
153    
154            //
155            // Try for better defaults, ignore errors.
156    
157            try {
158                setSourceEncoding(System.getProperty("file.encoding", "US-ASCII"));
159            }
160            catch (Exception e) {
161            }
162            try {
163                setOutput(new PrintWriter(System.err));
164            }
165            catch (Exception e) {
166            }
167            /*try {
168                setClasspath(System.getProperty("java.class.path"));
169            }
170            catch (Exception e) {
171            }*/
172    
173            try {
174                String target = System.getProperty("groovy.target.directory");
175                if (target != null) {
176                    setTargetDirectory(target);
177                }
178            }
179            catch (Exception e) {
180            }
181        }
182    
183    
184        /**
185         * Sets the Flags to the specified configuration, with defaults
186         * for those not supplied.
187         */
188    
189        public CompilerConfiguration(Properties configuration) throws ConfigurationException {
190            this();
191    
192            String text = null;
193            int numeric = 0;
194    
195    
196            //
197            // Warning level
198    
199            numeric = getWarningLevel();
200            try {
201                text = configuration.getProperty("groovy.warnings", "likely errors");
202                numeric = Integer.parseInt(text);
203            }
204            catch (NumberFormatException e) {
205                if (text.equals("none")) {
206                    numeric = WarningMessage.NONE;
207                }
208                else if (text.startsWith("likely")) {
209                    numeric = WarningMessage.LIKELY_ERRORS;
210                }
211                else if (text.startsWith("possible")) {
212                    numeric = WarningMessage.POSSIBLE_ERRORS;
213                }
214                else if (text.startsWith("paranoia")) {
215                    numeric = WarningMessage.PARANOIA;
216                }
217                else {
218                    throw new ConfigurationException("unrecogized groovy.warnings: " + text);
219                }
220            }
221    
222            setWarningLevel(numeric);
223    
224    
225            //
226            // Source file encoding
227    
228            text = configuration.getProperty("groovy.source.encoding");
229            if (text != null) {
230                setSourceEncoding(text);
231            }
232    
233    
234            //
235            // Target directory for classes
236    
237            text = configuration.getProperty("groovy.target.directory");
238            if (text != null) {
239                setTargetDirectory(text);
240            }
241    
242    
243            //
244            // Classpath
245    
246            text = configuration.getProperty("groovy.classpath");
247            if (text != null) {
248                setClasspath(text);
249            }
250    
251    
252            //
253            // Verbosity
254    
255            text = configuration.getProperty("groovy.output.verbose");
256            if (text != null && text.equals("true")) {
257                setVerbose(true);
258            }
259    
260    
261            //
262            // Debugging
263    
264            text = configuration.getProperty("groovy.output.debug");
265            if (text != null && text.equals("true")) {
266                setDebug(true);
267            }
268    
269    
270            //
271            // Tolerance
272    
273            numeric = 10;
274    
275            try {
276                text = configuration.getProperty("groovy.errors.tolerance", "10");
277                numeric = Integer.parseInt(text);
278            }
279            catch (NumberFormatException e) {
280                throw new ConfigurationException(e);
281            }
282    
283            setTolerance(numeric);
284    
285    
286            //
287            // Script Base Class
288    
289            text = configuration.getProperty("groovy.script.base");
290            setScriptBaseClass(text);
291    
292            text = configuration.getProperty("groovy.jsr");
293            if (text != null) {
294                setUseNewGroovy(text.equalsIgnoreCase("true"));
295            }
296            
297            
298            //
299            // recompilation options
300            //
301            text = configuration.getProperty("groovy.recompile");
302            if (text != null) {
303                setRecompileGroovySource(text.equalsIgnoreCase("true"));
304            }
305            
306            numeric = 100;
307            try {
308                text = configuration.getProperty("groovy.recompile.minimumIntervall", ""+numeric);
309                numeric = Integer.parseInt(text);
310            }
311            catch (NumberFormatException e) {
312                throw new ConfigurationException(e);
313            }
314            setMinimumRecompilationInterval(numeric);
315            
316            
317        }
318    
319    
320        /**
321         * Gets the currently configured warning level.  See WarningMessage
322         * for level details.
323         */
324        public int getWarningLevel() {
325            return this.warningLevel;
326        }
327    
328    
329        /**
330         * Sets the warning level.  See WarningMessage for level details.
331         */
332        public void setWarningLevel(int level) {
333            if (level < WarningMessage.NONE || level > WarningMessage.PARANOIA) {
334                this.warningLevel = WarningMessage.LIKELY_ERRORS;
335            }
336            else {
337                this.warningLevel = level;
338            }
339        }
340    
341    
342        /**
343         * Gets the currently configured source file encoding.
344         */
345        public String getSourceEncoding() {
346            return this.sourceEncoding;
347        }
348    
349    
350        /**
351         * Sets the encoding to be used when reading source files.
352         */
353        public void setSourceEncoding(String encoding) {
354            this.sourceEncoding = encoding;
355        }
356    
357    
358        /**
359         * Gets the currently configured output writer.
360         */
361        public PrintWriter getOutput() {
362            return this.output;
363        }
364    
365    
366        /**
367         * Sets the output writer.
368         */
369        public void setOutput(PrintWriter output) {
370            if (this.output == null) {
371                this.output = new PrintWriter(NullWriter.DEFAULT);
372            }
373            else {
374                this.output = output;
375            }
376        }
377    
378    
379        /**
380         * Gets the target directory for writing classes.
381         */
382        public File getTargetDirectory() {
383            return this.targetDirectory;
384        }
385    
386    
387        /**
388         * Sets the target directory.
389         */
390        public void setTargetDirectory(String directory) {
391            if (directory != null && directory.length() > 0) {
392                this.targetDirectory = new File(directory);
393            }
394            else {
395                this.targetDirectory = null;
396            }
397        }
398    
399    
400        /**
401         * Sets the target directory.
402         */
403        public void setTargetDirectory(File directory) {
404            this.targetDirectory = directory;
405        }
406    
407    
408        /**
409         * Gets the classpath.
410         */
411        public List getClasspath() {
412            return this.classpath;
413        }
414    
415    
416        /**
417         * Sets the classpath.
418         */
419        public void setClasspath(String classpath) {
420            this.classpath = new LinkedList();
421    
422            StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
423            while (tokenizer.hasMoreTokens()) {
424                this.classpath.add(tokenizer.nextToken());
425            }
426        }
427    
428    
429        /**
430         * Returns true if verbose operation has been requested.
431         */
432        public boolean getVerbose() {
433            return this.verbose;
434        }
435    
436    
437        /**
438         * Turns verbose operation on or off.
439         */
440        public void setVerbose(boolean verbose) {
441            this.verbose = verbose;
442        }
443    
444    
445        /**
446         * Returns true if debugging operation has been requested.
447         */
448        public boolean getDebug() {
449            return this.debug;
450        }
451    
452    
453        /**
454         * Turns debugging operation on or off.
455         */
456        public void setDebug(boolean debug) {
457            this.debug = debug;
458        }
459    
460    
461        /**
462         * Returns the requested error tolerance.
463         */
464        public int getTolerance() {
465            return this.tolerance;
466        }
467    
468    
469        /**
470         * Sets the error tolerance, which is the number of
471         * non-fatal errors (per unit) that should be tolerated before
472         * compilation is aborted.
473         */
474        public void setTolerance(int tolerance) {
475            this.tolerance = tolerance;
476        }
477    
478    
479        /**
480         * Gets the name of the base class for scripts.  It must be a subclass
481         * of Script.
482         */
483        public String getScriptBaseClass() {
484            return this.scriptBaseClass;
485        }
486    
487    
488        /**
489         * Sets the name of the base class for scripts.  It must be a subclass
490         * of Script.
491         */
492        public void setScriptBaseClass(String scriptBaseClass) {
493            this.scriptBaseClass = scriptBaseClass;
494        }
495    
496        /**
497         * Returns true if the new groovy (JSR) parser is enabled
498         */
499        public boolean isUseNewGroovy() {
500            return useNewGroovy;
501        }
502    
503        public void setUseNewGroovy(boolean useNewGroovy) {
504            this.useNewGroovy = useNewGroovy;
505        }
506    
507        public ParserPluginFactory getPluginFactory() {
508            if (pluginFactory == null) {
509                pluginFactory = ParserPluginFactory.newInstance(isUseNewGroovy());
510            }
511            return pluginFactory;
512        }
513    
514        public void setPluginFactory(ParserPluginFactory pluginFactory) {
515            this.pluginFactory = pluginFactory;
516        }
517    
518        /**
519         * Returns true if we are the JSR compatible Groovy language
520         */
521        public static boolean isJsrGroovy() {
522            return jsrGroovy;
523        }
524    
525        /**
526         * Should only be called by the JSR parser
527         */
528        public static void setJsrGroovy(boolean value) {
529            jsrGroovy = value;
530        }
531    
532        protected static boolean getDefaultJsrFlag() {
533            // TODO a temporary hack while we have 2 parsers
534            String property = null;
535            try {
536                 property = System.getProperty("groovy.jsr");
537            }
538            catch (Throwable e) {
539                // ignore security warnings
540            }
541            if (property != null) {
542                return "true".equalsIgnoreCase(property);
543            }
544            return DEFAULT_JSR_FLAG;
545        }
546    
547    
548        public String getDefaultScriptExtension() {
549            return defaultScriptExtension;
550        }
551    
552    
553        public void setDefaultScriptExtension(String defaultScriptExtension) {
554            this.defaultScriptExtension = defaultScriptExtension;
555        }
556        
557        public void setRecompileGroovySource(boolean recompile) {
558            recompileGroovySource = recompile;
559        }
560        
561        public boolean getRecompileGroovySource(){
562            return recompileGroovySource;
563        }
564        
565        public void setMinimumRecompilationInterval(int time) {
566            minimumRecompilationInterval = Math.max(0,time);
567        }
568        
569        public int getMinimumRecompilationInterval() {
570            return minimumRecompilationInterval;
571        }
572    
573    }