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 }