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