Clover coverage report - groovy - 1.0-beta-8
Coverage timestamp: Fri Dec 17 2004 14:55:55 GMT
file stats: LOC: 535   Methods: 43
NCLOC: 275   Classes: 2
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
GroovyShell.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  $Id: GroovyShell.java,v 1.37 2004/12/14 06:25:17 spullara Exp $
 3   
 
 4   
  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
 
 6   
  Redistribution and use of this software and associated documentation
 7   
  ("Software"), with or without modification, are permitted provided
 8   
  that the following conditions are met:
 9   
 
 10   
  1. Redistributions of source code must retain copyright
 11   
     statements and notices.  Redistributions must also contain a
 12   
     copy of this document.
 13   
 
 14   
  2. Redistributions in binary form must reproduce the
 15   
     above copyright notice, this list of conditions and the
 16   
     following disclaimer in the documentation and/or other
 17   
     materials provided with the distribution.
 18   
 
 19   
  3. The name "groovy" must not be used to endorse or promote
 20   
     products derived from this Software without prior written
 21   
     permission of The Codehaus.  For written permission,
 22   
     please contact info@codehaus.org.
 23   
 
 24   
  4. Products derived from this Software may not be called "groovy"
 25   
     nor may "groovy" appear in their names without prior written
 26   
     permission of The Codehaus. "groovy" is a registered
 27   
     trademark of The Codehaus.
 28   
 
 29   
  5. Due credit should be given to The Codehaus -
 30   
     http://groovy.codehaus.org/
 31   
 
 32   
  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
 33   
  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 34   
  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 35   
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 36   
  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 37   
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 38   
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 39   
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 40   
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 41   
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 42   
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 43   
  OF THE POSSIBILITY OF SUCH DAMAGE.
 44   
 
 45   
  */
 46   
 package groovy.lang;
 47   
 
 48   
 import groovy.ui.GroovyMain;
 49   
 import org.codehaus.groovy.control.CompilationFailedException;
 50   
 import org.codehaus.groovy.control.CompilerConfiguration;
 51   
 import org.codehaus.groovy.runtime.InvokerHelper;
 52   
 
 53   
 import java.io.ByteArrayInputStream;
 54   
 import java.io.File;
 55   
 import java.io.IOException;
 56   
 import java.io.InputStream;
 57   
 import java.lang.reflect.Constructor;
 58   
 import java.security.AccessController;
 59   
 import java.security.PrivilegedAction;
 60   
 import java.security.PrivilegedActionException;
 61   
 import java.security.PrivilegedExceptionAction;
 62   
 import java.util.List;
 63   
 
 64   
 /**
 65   
  * Represents a groovy shell capable of running arbitrary groovy scripts
 66   
  *
 67   
  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 68   
  * @author Guillaume Laforge
 69   
  * @version $Revision: 1.37 $
 70   
  */
 71   
 public class GroovyShell extends GroovyObjectSupport {
 72   
     public static final String[] EMPTY_ARGS = {
 73   
     };
 74   
 
 75   
     private GroovyClassLoader loader;
 76   
     private Binding context;
 77   
     private int counter;
 78   
 
 79  0
     public static void main(String[] args) {
 80  0
         GroovyMain.main(args);
 81   
     }
 82   
 
 83  0
     public GroovyShell() {
 84  0
         this(null, new Binding());
 85   
     }
 86   
 
 87  0
     public GroovyShell(Binding binding) {
 88  0
         this(null, binding);
 89   
     }
 90   
 
 91  0
     public GroovyShell(CompilerConfiguration config) {
 92  0
         this(new Binding(), config);
 93   
     }
 94   
 
 95  0
     public GroovyShell(Binding binding, CompilerConfiguration config) {
 96  0
         this(null, binding, config);
 97   
     }
 98   
 
 99  0
     public GroovyShell(ClassLoader parent, Binding binding) {
 100  0
         this(parent, binding, null);
 101   
     }
 102   
 
 103  0
     public GroovyShell(ClassLoader parent) {
 104  0
         this(parent, new Binding(), null);
 105   
     }
 106   
 
 107  0
     public GroovyShell(final ClassLoader parent, Binding binding, final CompilerConfiguration config) {
 108  0
         this.loader =
 109   
                 (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
 110  0
                     public Object run() {
 111  0
                         ClassLoader pcl = parent;
 112  0
                         if (pcl == null) {
 113  0
                             pcl = Thread.currentThread().getContextClassLoader();
 114  0
                             if (pcl == null) {
 115  0
                                 pcl = GroovyShell.class.getClassLoader();
 116   
                             }
 117   
                         }
 118  0
                         return new GroovyClassLoader(pcl, (config == null) ? new CompilerConfiguration() : config);
 119   
                     }
 120   
                 });
 121  0
         this.context = binding;
 122   
     }
 123   
 
 124   
     /**
 125   
      * Creates a child shell using a new ClassLoader which uses the parent shell's
 126   
      * class loader as its parent
 127   
      *
 128   
      * @param shell is the parent shell used for the variable bindings and the parent class loader
 129   
      */
 130  0
     public GroovyShell(GroovyShell shell) {
 131  0
         this(shell.loader, shell.context);
 132   
     }
 133   
 
 134  0
     public Binding getContext() {
 135  0
         return context;
 136   
     }
 137   
 
 138  0
     public Object getProperty(String property) {
 139  0
         Object answer = getVariable(property);
 140  0
         if (answer == null) {
 141  0
             answer = super.getProperty(property);
 142   
         }
 143  0
         return answer;
 144   
     }
 145   
 
 146  0
     public void setProperty(String property, Object newValue) {
 147  0
         setVariable(property, newValue);
 148  0
         try {
 149  0
             super.setProperty(property, newValue);
 150   
         } catch (GroovyRuntimeException e) {
 151   
             // ignore, was probably a dynamic property
 152   
         }
 153   
     }
 154   
 
 155   
     /**
 156   
      * A helper method which runs the given script file with the given command line arguments
 157   
      *
 158   
      * @param scriptFile the file of the script to run
 159   
      * @param list       the command line arguments to pass in
 160   
      */
 161  0
     public void run(File scriptFile, List list) throws CompilationFailedException, IOException {
 162  0
         String[] args = new String[list.size()];
 163  0
         run(scriptFile, (String[]) list.toArray(args));
 164   
     }
 165   
 
 166   
     /**
 167   
      * A helper method which runs the given cl script with the given command line arguments
 168   
      *
 169   
      * @param scriptText is the text content of the script
 170   
      * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
 171   
      * @param list       the command line arguments to pass in
 172   
      */
 173  0
     public void run(String scriptText, String fileName, List list) throws CompilationFailedException, IOException {
 174  0
         String[] args = new String[list.size()];
 175  0
         list.toArray(args);
 176  0
         run(scriptText, fileName, args);
 177   
     }
 178   
 
 179   
     /**
 180   
      * Runs the given script file name with the given command line arguments
 181   
      *
 182   
      * @param scriptFile the file name of the script to run
 183   
      * @param args       the command line arguments to pass in
 184   
      */
 185  0
     public void run(final File scriptFile, String[] args) throws CompilationFailedException, IOException {
 186  0
         String scriptName = scriptFile.getName();
 187  0
         int p = scriptName.lastIndexOf(".");
 188  0
         if (p++ >= 0) {
 189  0
             if (scriptName.substring(p).equals("java")) {
 190  0
                 System.err.println("error: cannot compile file with .java extension: " + scriptName);
 191  0
                 throw new CompilationFailedException(0, null);
 192   
             }
 193   
         }
 194   
 
 195   
         // Get the current context classloader and save it on the stack
 196  0
         final Thread thread = Thread.currentThread();
 197  0
         ClassLoader currentClassLoader = thread.getContextClassLoader();
 198   
 
 199   
         class DoSetContext implements PrivilegedAction {
 200   
             ClassLoader classLoader;
 201   
 
 202  0
             public DoSetContext(ClassLoader loader) {
 203  0
                 classLoader = loader;
 204   
             }
 205   
 
 206  0
             public Object run() {
 207  0
                 thread.setContextClassLoader(classLoader);
 208  0
                 return null;
 209   
             }
 210   
         }
 211   
         ;
 212   
 
 213  0
         AccessController.doPrivileged(new DoSetContext(loader));
 214   
 
 215   
         // Parse the script, generate the class, and invoke the main method.  This is a little looser than
 216   
         // if you are compiling the script because the JVM isn't executing the main method.
 217  0
         Class scriptClass;
 218  0
         try {
 219  0
             scriptClass = (Class) AccessController.doPrivileged(new PrivilegedExceptionAction() {
 220  0
                 public Object run() throws CompilationFailedException, IOException {
 221  0
                     return loader.parseClass(scriptFile);
 222   
                 }
 223   
             });
 224   
         } catch (PrivilegedActionException pae) {
 225  0
             Exception e = pae.getException();
 226  0
             if (e instanceof CompilationFailedException) {
 227  0
                 throw (CompilationFailedException) e;
 228  0
             } else if (e instanceof IOException) {
 229  0
                 throw (IOException) e;
 230   
             } else {
 231  0
                 throw (RuntimeException) pae.getException();
 232   
             }
 233   
         }
 234   
 
 235  0
         runMainOrTestOrRunnable(scriptClass, args);
 236   
 
 237   
         // Set the context classloader back to what it was.
 238  0
         AccessController.doPrivileged(new DoSetContext(currentClassLoader));
 239   
     }
 240   
 
 241   
     /**
 242   
      * if (theClass has a main method) {
 243   
      * run the main method
 244   
      * } else if (theClass instanceof GroovyTestCase) {
 245   
      * use the test runner to run it
 246   
      * } else if (theClass implements Runnable) {
 247   
      * if (theClass has a constructor with String[] params)
 248   
      * instanciate theClass with this constructor and run
 249   
      * else if (theClass has a no-args constructor)
 250   
      * instanciate theClass with the no-args constructor and run
 251   
      * }
 252   
      */
 253  0
     private void runMainOrTestOrRunnable(Class scriptClass, String[] args) {
 254  0
         try {
 255   
             // let's find a main method
 256  0
             scriptClass.getMethod("main", new Class[]{String[].class});
 257   
             // if that main method exist, invoke it
 258  0
             InvokerHelper.invokeMethod(scriptClass, "main", new Object[]{args});
 259   
         } catch (NoSuchMethodException e) {
 260   
             // As no main() method was found, let's see if it's a unit test
 261   
             // if it's a unit test extending GroovyTestCase, run it with JUnit's TextRunner
 262  0
             if (isUnitTestCase(scriptClass)) {
 263  0
                 runTest(scriptClass);
 264   
             }
 265   
             // no main() method, not a unit test,
 266   
             // if it implements Runnable, try to instanciate it
 267  0
             else if (Runnable.class.isAssignableFrom(scriptClass)) {
 268  0
                 Constructor constructor = null;
 269  0
                 Runnable runnable = null;
 270  0
                 Throwable reason = null;
 271  0
                 try {
 272   
                     // first, fetch the constructor taking String[] as parameter
 273  0
                     constructor = scriptClass.getConstructor(new Class[]{(new String[]{}).getClass()});
 274  0
                     try {
 275   
                         // instanciate a runnable and run it
 276  0
                         runnable = (Runnable) constructor.newInstance(new Object[]{args});
 277   
                     } catch (Throwable t) {
 278  0
                         reason = t;
 279   
                     }
 280   
                 } catch (NoSuchMethodException e1) {
 281  0
                     try {
 282   
                         // otherwise, find the default constructor
 283  0
                         constructor = scriptClass.getConstructor(new Class[]{});
 284  0
                         try {
 285   
                             // instanciate a runnable and run it
 286  0
                             runnable = (Runnable) constructor.newInstance(new Object[]{});
 287   
                         } catch (Throwable t) {
 288  0
                             reason = t;
 289   
                         }
 290   
                     } catch (NoSuchMethodException nsme) {
 291  0
                         reason = nsme;
 292   
                     }
 293   
                 }
 294  0
                 if (constructor != null && runnable != null) {
 295  0
                     runnable.run();
 296   
                 } else {
 297  0
                     throw new GroovyRuntimeException("This script or class could not be run. ", reason);
 298   
                 }
 299   
             } else {
 300  0
                 throw new GroovyRuntimeException("This script or class could not be run. \n" +
 301   
                         "It should either: \n" +
 302   
                         "- have a main method, \n" +
 303   
                         "- be a class extending GroovyTestCase, \n" +
 304   
                         "- or implement the Runnable interface.");
 305   
             }
 306   
         }
 307   
     }
 308   
 
 309   
     /**
 310   
      * Run the specified class extending GroovyTestCase as a unit test.
 311   
      * This is done through reflection, to avoid adding a dependency to the JUnit framework.
 312   
      * Otherwise, developers embedding Groovy and using GroovyShell to load/parse/compile
 313   
      * groovy scripts and classes would have to add another dependency on their classpath.
 314   
      *
 315   
      * @param scriptClass the class to be run as a unit test
 316   
      */
 317  0
     private void runTest(Class scriptClass) {
 318  0
         try {
 319  0
             InvokerHelper.invokeStaticMethod("junit.textui.TestRunner", "run", new Object[]{scriptClass});
 320   
         } catch (Exception e) {
 321  0
             throw new GroovyRuntimeException("Failed to run the unit test. JUnit is not on the Classpath.");
 322   
         }
 323   
     }
 324   
 
 325   
     /**
 326   
      * Utility method to check through reflection if the parsed class extends GroovyTestCase.
 327   
      *
 328   
      * @param scriptClass the class we want to know if it extends GroovyTestCase
 329   
      * @return true if the class extends groovy.util.GroovyTestCase
 330   
      */
 331  0
     private boolean isUnitTestCase(Class scriptClass) {
 332   
         // check if the parsed class is a GroovyTestCase,
 333   
         // so that it is possible to run it as a JUnit test
 334  0
         boolean isUnitTestCase = false;
 335  0
         try {
 336  0
             try {
 337  0
                 Class testCaseClass = this.loader.loadClass("groovy.util.GroovyTestCase");
 338   
                 // if scriptClass extends testCaseClass
 339  0
                 if (testCaseClass.isAssignableFrom(scriptClass)) {
 340  0
                     isUnitTestCase = true;
 341   
                 }
 342   
             } catch (ClassNotFoundException e) {
 343   
                 // fall through
 344   
             }
 345   
         } catch (Throwable e) {
 346   
             // fall through
 347   
         }
 348  0
         return isUnitTestCase;
 349   
     }
 350   
 
 351   
     /**
 352   
      * Runs the given script text with command line arguments
 353   
      *
 354   
      * @param scriptText is the text content of the script
 355   
      * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
 356   
      * @param args       the command line arguments to pass in
 357   
      */
 358  0
     public void run(String scriptText, String fileName, String[] args) throws CompilationFailedException, IOException {
 359  0
         run(new ByteArrayInputStream(scriptText.getBytes()), fileName, args);
 360   
     }
 361   
 
 362   
     /**
 363   
      * Runs the given script with command line arguments
 364   
      *
 365   
      * @param in       the stream reading the script
 366   
      * @param fileName is the logical file name of the script (which is used to create the class name of the script)
 367   
      * @param args     the command line arguments to pass in
 368   
      */
 369  0
     public Object run(final InputStream in, final String fileName, String[] args) throws CompilationFailedException, IOException {
 370  0
         GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() {
 371  0
             public Object run() {
 372  0
                 return new GroovyCodeSource(in, fileName, "/groovy/shell");
 373   
             }
 374   
         });
 375  0
         Class scriptClass = parseClass(gcs);
 376  0
         runMainOrTestOrRunnable(scriptClass, args);
 377  0
         return null;
 378   
     }
 379   
 
 380  0
     public Object getVariable(String name) {
 381  0
         return context.getVariables().get(name);
 382   
     }
 383   
 
 384  0
     public void setVariable(String name, Object value) {
 385  0
         context.setVariable(name, value);
 386   
     }
 387   
 
 388   
     /**
 389   
      * Evaluates some script against the current Binding and returns the result
 390   
      *
 391   
      * @param codeSource
 392   
      * @return
 393   
      * @throws CompilationFailedException
 394   
      * @throws IOException
 395   
      */
 396  0
     public Object evaluate(GroovyCodeSource codeSource) throws CompilationFailedException, IOException {
 397  0
         Script script = parse(codeSource);
 398  0
         return script.run();
 399   
     }
 400   
 
 401   
     /**
 402   
      * Evaluates some script against the current Binding and returns the result
 403   
      *
 404   
      * @param scriptText the text of the script
 405   
      * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
 406   
      */
 407  0
     public Object evaluate(String scriptText, String fileName) throws CompilationFailedException, ClassNotFoundException, IOException {
 408  0
         return evaluate(new ByteArrayInputStream(scriptText.getBytes()), fileName);
 409   
     }
 410   
 
 411   
     /**
 412   
      * Evaluates some script against the current Binding and returns the result.
 413   
      * The .class file created from the script is given the supplied codeBase
 414   
      */
 415  0
     public Object evaluate(String scriptText, String fileName, String codeBase) throws CompilationFailedException, IOException {
 416  0
         return evaluate(new GroovyCodeSource(new ByteArrayInputStream(scriptText.getBytes()), fileName, codeBase));
 417   
     }
 418   
 
 419   
     /**
 420   
      * Evaluates some script against the current Binding and returns the result
 421   
      *
 422   
      * @param file is the file of the script (which is used to create the class name of the script)
 423   
      */
 424  0
     public Object evaluate(File file) throws CompilationFailedException, IOException {
 425  0
         return evaluate(new GroovyCodeSource(file));
 426   
     }
 427   
 
 428   
     /**
 429   
      * Evaluates some script against the current Binding and returns the result
 430   
      *
 431   
      * @param scriptText the text of the script
 432   
      */
 433  0
     public Object evaluate(String scriptText) throws CompilationFailedException, IOException {
 434  0
         return evaluate(new ByteArrayInputStream(scriptText.getBytes()), generateScriptName());
 435   
     }
 436   
 
 437   
     /**
 438   
      * Evaluates some script against the current Binding and returns the result
 439   
      *
 440   
      * @param in the stream reading the script
 441   
      */
 442  0
     public Object evaluate(InputStream in) throws CompilationFailedException, IOException {
 443  0
         return evaluate(in, generateScriptName());
 444   
     }
 445   
 
 446   
     /**
 447   
      * Evaluates some script against the current Binding and returns the result
 448   
      *
 449   
      * @param in       the stream reading the script
 450   
      * @param fileName is the logical file name of the script (which is used to create the class name of the script)
 451   
      */
 452  0
     public Object evaluate(InputStream in, String fileName) throws CompilationFailedException, IOException {
 453  0
         Script script = null;
 454  0
         try {
 455  0
             script = parse(in, fileName);
 456  0
             return script.run();
 457   
         } finally {
 458  0
             if (script != null) {
 459  0
                 InvokerHelper.removeClass(script.getClass());
 460   
             }
 461   
         }
 462   
     }
 463   
 
 464   
     /**
 465   
      * Parses the given script and returns it ready to be run
 466   
      *
 467   
      * @param in       the stream reading the script
 468   
      * @param fileName is the logical file name of the script (which is used to create the class name of the script)
 469   
      * @return the parsed script which is ready to be run via @link Script.run()
 470   
      */
 471  0
     public Script parse(final InputStream in, final String fileName) throws CompilationFailedException, IOException {
 472  0
         GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() {
 473  0
             public Object run() {
 474  0
                 return new GroovyCodeSource(in, fileName, "/groovy/shell");
 475   
             }
 476   
         });
 477  0
         return parse(gcs);
 478   
     }
 479   
 
 480   
     /**
 481   
      * Parses the groovy code contained in codeSource and returns a java class.
 482   
      */
 483  0
     private Class parseClass(final GroovyCodeSource codeSource) throws CompilationFailedException, IOException {
 484   
         // Don't cache scripts
 485  0
         return loader.parseClass(codeSource, false);
 486   
     }
 487   
 
 488   
     /**
 489   
      * Parses the given script and returns it ready to be run.  When running in a secure environment
 490   
      * (-Djava.security.manager) codeSource.getCodeSource() determines what policy grants should be
 491   
      * given to the script.
 492   
      *
 493   
      * @param codeSource
 494   
      * @return
 495   
      */
 496  0
     public Script parse(final GroovyCodeSource codeSource) throws CompilationFailedException, IOException {
 497  0
         return InvokerHelper.createScript(parseClass(codeSource), context);
 498   
     }
 499   
 
 500   
     /**
 501   
      * Parses the given script and returns it ready to be run
 502   
      *
 503   
      * @param file is the file of the script (which is used to create the class name of the script)
 504   
      */
 505  0
     public Script parse(File file) throws CompilationFailedException, IOException {
 506  0
         return parse(new GroovyCodeSource(file));
 507   
     }
 508   
 
 509   
     /**
 510   
      * Parses the given script and returns it ready to be run
 511   
      *
 512   
      * @param scriptText the text of the script
 513   
      */
 514  0
     public Script parse(String scriptText) throws CompilationFailedException, IOException {
 515  0
         return parse(new ByteArrayInputStream(scriptText.getBytes()), generateScriptName());
 516   
     }
 517   
 
 518  0
     public Script parse(String scriptText, String fileName) throws CompilationFailedException, IOException {
 519  0
         return parse(new ByteArrayInputStream(scriptText.getBytes()), fileName);
 520   
     }
 521   
 
 522   
     /**
 523   
      * Parses the given script and returns it ready to be run
 524   
      *
 525   
      * @param in the stream reading the script
 526   
      */
 527  0
     public Script parse(InputStream in) throws CompilationFailedException, IOException {
 528  0
         return parse(in, generateScriptName());
 529   
     }
 530   
 
 531  0
     protected synchronized String generateScriptName() {
 532  0
         return "Script" + (++counter) + ".groovy";
 533   
     }
 534   
 }
 535