001    /*
002     $Id: CompilerConfiguration.java,v 1.11 2005/02/28 14:47:10 jstrachan Exp $
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     * @version $Id: CompilerConfiguration.java,v 1.11 2005/02/28 14:47:10 jstrachan Exp $
065     */
066    
067    public class CompilerConfiguration {
068        public static final CompilerConfiguration DEFAULT = new CompilerConfiguration();
069    
070        /** Whether to use the JSR parser or not if no property is explicitly stated */
071        protected static final boolean DEFAULT_JSR_FLAG = true;
072    
073        private static boolean jsrGroovy;
074    
075        /**
076         * See WarningMessage for levels
077         */
078        private int warningLevel;
079        /**
080         * Encoding for source files
081         */
082        private String sourceEncoding;
083        /**
084         * A PrintWriter for communicating with the user
085         */
086        private PrintWriter output;
087        /**
088         * Directory into which to write classes
089         */
090        private File targetDirectory;
091        /**
092         * Classpath for use during compilation
093         */
094        private LinkedList classpath;
095        /**
096         * If true, the compiler should produce action information
097         */
098        private boolean verbose;
099        /**
100         * If true, debugging code should be activated
101         */
102        private boolean debug;
103        /**
104         * The number of non-fatal errors to allow before bailing
105         */
106        private int tolerance;
107        /**
108         * Base class name for scripts (must derive from Script)
109         */
110        private String scriptBaseClass;
111        /**
112         * should we use the New JSR Groovy parser or stay with the static one
113         */
114        private boolean useNewGroovy = getDefaultJsrFlag();
115    
116        private ParserPluginFactory pluginFactory;
117    
118    
119        /**
120         * Sets the Flags to defaults.
121         */
122    
123        public CompilerConfiguration() {
124            //
125            // Set in safe defaults
126    
127            setWarningLevel(WarningMessage.LIKELY_ERRORS);
128            setSourceEncoding("US-ASCII");
129            setOutput(null);
130            setTargetDirectory((File) null);
131            setClasspath("");
132            setVerbose(false);
133            setDebug(false);
134            setTolerance(10);
135            setScriptBaseClass(null);
136    
137    
138            //
139            // Try for better defaults, ignore errors.
140    
141            try {
142                setSourceEncoding(System.getProperty("file.encoding", "US-ASCII"));
143            }
144            catch (Exception e) {
145            }
146            try {
147                setOutput(new PrintWriter(System.err));
148            }
149            catch (Exception e) {
150            }
151            try {
152                setClasspath(System.getProperty("java.class.path"));
153            }
154            catch (Exception e) {
155            }
156    
157            try {
158                String target = System.getProperty("groovy.target.directory");
159                if (target != null) {
160                    setTargetDirectory(target);
161                }
162            }
163            catch (Exception e) {
164            }
165        }
166    
167    
168        /**
169         * Sets the Flags to the specified configuration, with defaults
170         * for those not supplied.
171         */
172    
173        public CompilerConfiguration(Properties configuration) throws ConfigurationException {
174            this();
175    
176            String text = null;
177            int numeric = 0;
178    
179    
180            //
181            // Warning level
182    
183            numeric = getWarningLevel();
184            try {
185                text = configuration.getProperty("groovy.warnings", "likely errors");
186                numeric = Integer.parseInt(text);
187            }
188            catch (NumberFormatException e) {
189                if (text.equals("none")) {
190                    numeric = WarningMessage.NONE;
191                }
192                else if (text.startsWith("likely")) {
193                    numeric = WarningMessage.LIKELY_ERRORS;
194                }
195                else if (text.startsWith("possible")) {
196                    numeric = WarningMessage.POSSIBLE_ERRORS;
197                }
198                else if (text.startsWith("paranoia")) {
199                    numeric = WarningMessage.PARANOIA;
200                }
201                else {
202                    throw new ConfigurationException("unrecogized groovy.warnings: " + text);
203                }
204            }
205    
206            setWarningLevel(numeric);
207    
208    
209            //
210            // Source file encoding
211    
212            text = configuration.getProperty("groovy.source.encoding");
213            if (text != null) {
214                setSourceEncoding(text);
215            }
216    
217    
218            //
219            // Target directory for classes
220    
221            text = configuration.getProperty("groovy.target.directory");
222            if (text != null) {
223                setTargetDirectory(text);
224            }
225    
226    
227            //
228            // Classpath
229    
230            text = configuration.getProperty("groovy.classpath");
231            if (text != null) {
232                setClasspath(text);
233            }
234    
235    
236            //
237            // Verbosity
238    
239            text = configuration.getProperty("groovy.output.verbose");
240            if (text != null && text.equals("true")) {
241                setVerbose(true);
242            }
243    
244    
245            //
246            // Debugging
247    
248            text = configuration.getProperty("groovy.output.debug");
249            if (text != null && text.equals("true")) {
250                setDebug(true);
251            }
252    
253    
254            //
255            // Tolerance
256    
257            numeric = 10;
258    
259            try {
260                text = configuration.getProperty("groovy.errors.tolerance", "10");
261                numeric = Integer.parseInt(text);
262            }
263            catch (NumberFormatException e) {
264                throw new ConfigurationException(e);
265            }
266    
267            setTolerance(numeric);
268    
269    
270            //
271            // Script Base Class
272    
273            text = configuration.getProperty("groovy.script.base");
274            setScriptBaseClass(text);
275    
276            text = configuration.getProperty("groovy.jsr");
277            if (text != null) {
278                setUseNewGroovy(text.equalsIgnoreCase("true"));
279            }
280        }
281    
282    
283        /**
284         * Gets the currently configured warning level.  See WarningMessage
285         * for level details.
286         */
287    
288        public int getWarningLevel() {
289            return this.warningLevel;
290        }
291    
292    
293        /**
294         * Sets the warning level.  See WarningMessage for level details.
295         */
296    
297        public void setWarningLevel(int level) {
298            if (level < WarningMessage.NONE || level > WarningMessage.PARANOIA) {
299                this.warningLevel = WarningMessage.LIKELY_ERRORS;
300            }
301            else {
302                this.warningLevel = level;
303            }
304        }
305    
306    
307        /**
308         * Gets the currently configured source file encoding.
309         */
310    
311        public String getSourceEncoding() {
312            return this.sourceEncoding;
313        }
314    
315    
316        /**
317         * Sets the encoding to be used when reading source files.
318         */
319    
320        public void setSourceEncoding(String encoding) {
321            this.sourceEncoding = encoding;
322        }
323    
324    
325        /**
326         * Gets the currently configured output writer.
327         */
328    
329        public PrintWriter getOutput() {
330            return this.output;
331        }
332    
333    
334        /**
335         * Sets the output writer.
336         */
337    
338        public void setOutput(PrintWriter output) {
339            if (this.output == null) {
340                this.output = new PrintWriter(NullWriter.DEFAULT);
341            }
342            else {
343                this.output = output;
344            }
345        }
346    
347    
348        /**
349         * Gets the target directory for writing classes.
350         */
351    
352        public File getTargetDirectory() {
353            return this.targetDirectory;
354        }
355    
356    
357        /**
358         * Sets the target directory.
359         */
360    
361        public void setTargetDirectory(String directory) {
362            if (directory != null && directory.length() > 0) {
363                this.targetDirectory = new File(directory);
364            }
365            else {
366                this.targetDirectory = null;
367            }
368        }
369    
370    
371        /**
372         * Sets the target directory.
373         */
374    
375        public void setTargetDirectory(File directory) {
376            this.targetDirectory = directory;
377        }
378    
379    
380        /**
381         * Gets the classpath.
382         */
383    
384        public List getClasspath() {
385            return this.classpath;
386        }
387    
388    
389        /**
390         * Sets the output writer.
391         */
392    
393        public void setClasspath(String classpath) {
394            this.classpath = new LinkedList();
395    
396            StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
397            while (tokenizer.hasMoreTokens()) {
398                this.classpath.add(tokenizer.nextToken());
399            }
400        }
401    
402    
403        /**
404         * Returns true if verbose operation has been requested.
405         */
406    
407        public boolean getVerbose() {
408            return this.verbose;
409        }
410    
411    
412        /**
413         * Turns verbose operation on or off.
414         */
415    
416        public void setVerbose(boolean verbose) {
417            this.verbose = verbose;
418        }
419    
420    
421        /**
422         * Returns true if debugging operation has been requested.
423         */
424    
425        public boolean getDebug() {
426            return this.debug;
427        }
428    
429    
430        /**
431         * Turns debugging operation on or off.
432         */
433    
434        public void setDebug(boolean debug) {
435            this.debug = debug;
436        }
437    
438    
439        /**
440         * Returns the requested error tolerance.
441         */
442    
443        public int getTolerance() {
444            return this.tolerance;
445        }
446    
447    
448        /**
449         * Sets the error tolerance, which is the number of
450         * non-fatal errors (per unit) that should be tolerated before
451         * compilation is aborted.
452         */
453    
454        public void setTolerance(int tolerance) {
455            this.tolerance = tolerance;
456        }
457    
458    
459        /**
460         * Gets the name of the base class for scripts.  It must be a subclass
461         * of Script.
462         */
463    
464        public String getScriptBaseClass() {
465            return this.scriptBaseClass;
466        }
467    
468    
469        /**
470         * Sets the name of the base class for scripts.  It must be a subclass
471         * of Script.
472         */
473        public void setScriptBaseClass(String scriptBaseClass) {
474            this.scriptBaseClass = scriptBaseClass;
475        }
476    
477        /**
478         * Returns true if the new groovy (JSR) parser is enabled
479         */
480        public boolean isUseNewGroovy() {
481            return useNewGroovy;
482        }
483    
484        public void setUseNewGroovy(boolean useNewGroovy) {
485            this.useNewGroovy = useNewGroovy;
486        }
487    
488        public ParserPluginFactory getPluginFactory() {
489            if (pluginFactory == null) {
490                pluginFactory = ParserPluginFactory.newInstance(isUseNewGroovy());
491            }
492            return pluginFactory;
493        }
494    
495        public void setPluginFactory(ParserPluginFactory pluginFactory) {
496            this.pluginFactory = pluginFactory;
497        }
498    
499        /**
500         * Returns true if we are the JSR compatible Groovy language
501         */
502        public static boolean isJsrGroovy() {
503            return jsrGroovy;
504        }
505    
506        /**
507         * Should only be called by the JSR parser
508         */
509        public static void setJsrGroovy(boolean value) {
510            jsrGroovy = value;
511        }
512    
513        protected static boolean getDefaultJsrFlag() {
514            // TODO a temporary hack while we have 2 parsers
515            String property = null;
516            try {
517                 property = System.getProperty("groovy.jsr");
518            }
519            catch (Throwable e) {
520                // ignore security warnings
521            }
522            if (property != null) {
523                return "true".equalsIgnoreCase(property);
524            }
525            return DEFAULT_JSR_FLAG;
526        }
527    
528    }
529    
530    
531    
532