001    /*
002     $Id: Script.java 4262 2006-11-25 13:27:06Z blackdrag $
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    package groovy.lang;
047    
048    import org.codehaus.groovy.ast.expr.ArgumentListExpression;
049    import org.codehaus.groovy.control.CompilationFailedException;
050    import org.codehaus.groovy.runtime.DefaultGroovyMethods;
051    import org.codehaus.groovy.runtime.InvokerHelper;
052    
053    import java.io.File;
054    import java.io.IOException;
055    
056    /**
057     * This object represents a Groovy script
058     *
059     * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
060     * @author Guillaume Laforge
061     * @version $Revision: 4262 $
062     */
063    public abstract class Script extends GroovyObjectSupport {
064        private Binding binding = new Binding();
065    
066        protected Script() {
067        }
068    
069        protected Script(Binding binding) {
070            this.binding = binding;
071        }
072    
073        public Binding getBinding() {
074            return binding;
075        }
076    
077        public void setBinding(Binding binding) {
078            this.binding = binding;
079        }
080    
081        public Object getProperty(String property) {
082            try {
083                return binding.getVariable(property);
084            } catch (MissingPropertyException e) {
085                return super.getProperty(property);
086            }
087        }
088    
089        public void setProperty(String property, Object newValue) {
090            if ("binding".equals(property))
091                setBinding((Binding) newValue);
092            else
093                binding.setVariable(property, newValue);
094        }
095    
096        /**
097         * Invoke a method (or closure in the binding) defined.
098         *
099         * @param name method to call
100         * @param args arguments to pass to the method
101         * @return value
102         */
103        public Object invokeMethod(String name, Object args) {
104            try {
105                return super.invokeMethod(name, args);
106            }
107                    // if the method was not found in the current scope (the script's methods)
108                    // let's try to see if there's a method closure with the same name in the binding
109            catch (MissingMethodException mme) {
110                try {
111                    if (name.equals(mme.getMethod())) {
112                        Object boundClosure = binding.getVariable(name);
113                        if (boundClosure != null && boundClosure instanceof Closure) {
114                            return ((Closure) boundClosure).call((Object[])args);
115                        } else {
116                            throw mme;
117                        }
118                    } else {
119                        throw mme;
120                    }
121                } catch (MissingPropertyException mpe) {
122                    throw mme;
123                }
124            }
125        }
126    
127        /**
128         * The main instance method of a script which has variables in scope
129         * as defined by the current {@link Binding} instance.
130         */
131        public abstract Object run();
132    
133        // println helper methods
134    
135        /**
136         * Prints a newline to the current 'out' variable which should be a PrintWriter
137         * or at least have a println() method defined on it.
138         * If there is no 'out' property then print to standard out.
139         */
140        public void println() {
141            Object object;
142    
143            try {
144                object = getProperty("out");
145            } catch (MissingPropertyException e) {
146                System.out.println();
147                return;
148            }
149    
150            InvokerHelper.invokeMethod(object, "println", ArgumentListExpression.EMPTY_ARRAY);
151        }
152    
153        /**
154         * Prints the value to the current 'out' variable which should be a PrintWriter
155         * or at least have a print() method defined on it.
156         * If there is no 'out' property then print to standard out.
157         */
158        public void print(Object value) {
159            Object object;
160    
161            try {
162                object = getProperty("out");
163            } catch (MissingPropertyException e) {
164                DefaultGroovyMethods.print(System.out,value);
165                return;
166            }
167    
168            InvokerHelper.invokeMethod(object, "print", new Object[]{value});
169        }
170    
171        /**
172         * Prints the value and a newline to the current 'out' variable which should be a PrintWriter
173         * or at least have a println() method defined on it.
174         * If there is no 'out' property then print to standard out.
175         */
176        public void println(Object value) {
177            Object object;
178    
179            try {
180                object = getProperty("out");
181            } catch (MissingPropertyException e) {
182                DefaultGroovyMethods.println(System.out,value);
183                return;
184            }
185    
186            InvokerHelper.invokeMethod(object, "println", new Object[]{value});
187        }
188    
189        /**
190         * A helper method to allow the dynamic evaluation of groovy expressions using this
191         * scripts binding as the variable scope
192         *
193         * @param expression is the Groovy script expression to evaluate
194         */
195        public Object evaluate(String expression) throws CompilationFailedException, IOException {
196            GroovyShell shell = new GroovyShell(binding);
197            return shell.evaluate(expression);
198        }
199    
200        /**
201         * A helper method to allow the dynamic evaluation of groovy expressions using this
202         * scripts binding as the variable scope
203         *
204         * @param file is the Groovy script to evaluate
205         */
206        public Object evaluate(File file) throws CompilationFailedException, IOException {
207            GroovyShell shell = new GroovyShell(binding);
208            return shell.evaluate(file);
209        }
210    
211        /**
212         * A helper method to allow scripts to be run taking command line arguments
213         */
214        public void run(File file, String[] arguments) throws CompilationFailedException, IOException {
215            GroovyShell shell = new GroovyShell(binding);
216            shell.run(file, arguments);
217        }
218    }