Source Code Cross Referenced for ScriptEvaluator.java in  » Scripting » janino-2.5.11 » org » codehaus » janino » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » janino 2.5.11 » org.codehaus.janino 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Janino - An embedded Java[TM] compiler
0003:         *
0004:         * Copyright (c) 2001-2007, Arno Unkrig
0005:         * All rights reserved.
0006:         *
0007:         * Redistribution and use in source and binary forms, with or without
0008:         * modification, are permitted provided that the following conditions
0009:         * are met:
0010:         *
0011:         *    1. Redistributions of source code must retain the above copyright
0012:         *       notice, this list of conditions and the following disclaimer.
0013:         *    2. Redistributions in binary form must reproduce the above
0014:         *       copyright notice, this list of conditions and the following
0015:         *       disclaimer in the documentation and/or other materials
0016:         *       provided with the distribution.
0017:         *    3. The name of the author may not be used to endorse or promote
0018:         *       products derived from this software without specific prior
0019:         *       written permission.
0020:         *
0021:         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0022:         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0023:         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024:         * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0025:         * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0026:         * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
0027:         * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028:         * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
0029:         * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
0030:         * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
0031:         * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0032:         */
0033:
0034:        package org.codehaus.janino;
0035:
0036:        import java.io.*;
0037:        import java.lang.reflect.*;
0038:        import java.util.HashMap;
0039:        import java.util.Map;
0040:
0041:        import org.codehaus.janino.Parser.ParseException;
0042:        import org.codehaus.janino.Scanner.ScanException;
0043:
0044:        /**
0045:         * An engine that executes a script in Java<sup>TM</sup> bytecode.
0046:         * <p>
0047:         * The syntax of the script to compile is a sequence of import declarations (not allowed if you
0048:         * compile many scripts at a time, see below) followed by a
0049:         * sequence of statements, as defined in the
0050:         * <a href="http://java.sun.com/docs/books/jls/second_edition">Java Language Specification, 2nd
0051:         * edition</a>, sections
0052:         * <a href="http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#70209">7.5</a>
0053:         * and
0054:         * <a href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#101241">14</a>.
0055:         * <p>
0056:         * Example:
0057:         * <pre>
0058:         *   import java.text.*;
0059:         * 
0060:         *   System.out.println("HELLO");
0061:         *   System.out.println(new DecimalFormat("####,###.##").format(a));
0062:         * </pre>
0063:         * (Notice that this expression refers to a parameter "a", as explained below.)
0064:         * <p>
0065:         * The script may complete abnormally, e.g. through a RETURN statement:
0066:         * <pre>
0067:         *   if (a == null) {
0068:         *       System.out.println("Oops!");
0069:         *       return;
0070:         *   }
0071:         * </pre>
0072:         * Optionally, the script may be declared with a non-void return type. In this case, the last
0073:         * statement of the script must be a RETURN statement (or a THROW statement), and all RETURN
0074:         * statements in the script must return a value with the given type.
0075:         * <p>
0076:         * The script evaluator is implemented by creating and compiling a temporary compilation unit
0077:         * defining one class with one method the body of which consists of the statements of the
0078:         * script.
0079:         * <p>
0080:         * To set up a {@link ScriptEvaluator} object, proceed as follows:
0081:         * <ol>
0082:         *   <li>
0083:         *   Create the {@link ScriptEvaluator} using {@link #ScriptEvaluator()}
0084:         *   <li>
0085:         *   Configure the {@link ScriptEvaluator} by calling any of the following methods:
0086:         *   <ul>
0087:         *      <li>{@link #setReturnType(Class)}
0088:         *      <li>{@link #setParameters(String[], Class[])}
0089:         *      <li>{@link #setThrownExceptions(Class[])}
0090:         *      <li>{@link org.codehaus.janino.SimpleCompiler#setParentClassLoader(ClassLoader)}
0091:         *      <li>{@link org.codehaus.janino.ClassBodyEvaluator#setDefaultImports(String[])}
0092:         *   </ul>
0093:         *   <li>
0094:         *   Call any of the {@link org.codehaus.janino.Cookable#cook(Scanner)} methods to scan,
0095:         *   parse, compile and load the script into the JVM.
0096:         * </ol>
0097:         * After the {@link ScriptEvaluator} object is created, the script can be executed as often with
0098:         * different parameter values (see {@link #evaluate(Object[])}). This execution is very fast,
0099:         * compared to the compilation.
0100:         * <p>
0101:         * Less common methods exist that allow for the specification of the name of the generated class,
0102:         * the class it extends, the interfaces it implements, the name of the method that executes the
0103:         * script, the exceptions that this method (i.e. the script) is allowed to throw, and the
0104:         * {@link ClassLoader} that is used to define the generated class and to load classes referenced by
0105:         * the script.
0106:         * <p>
0107:         * Alternatively, a number of "convenience constructors" exist that execute the steps described
0108:         * above instantly. Their use is discouraged.
0109:         * <p>
0110:         * If you want to compile many scripts at the same time, you have the option to cook an
0111:         * <i>array</i> of scripts in one {@link ScriptEvaluator} by using the following methods:
0112:         * <ul>
0113:         *   <li>{@link #setMethodNames(String[])}
0114:         *   <li>{@link #setParameters(String[][], Class[][])}
0115:         *   <li>{@link #setReturnTypes(Class[])}
0116:         *   <li>{@link #setStaticMethod(boolean[])}
0117:         *   <li>{@link #setThrownExceptions(Class[][])}
0118:         *   <li>{@link #cook(Scanner[])}
0119:         *   <li>{@link #evaluate(int, Object[])}
0120:         * </ul>
0121:         * Notice that these methods have array parameters in contrast to their one-script brethren.
0122:         */
0123:        public class ScriptEvaluator extends ClassBodyEvaluator {
0124:
0125:            protected boolean[] optionalStaticMethod = null;
0126:            protected Class[] optionalReturnTypes = null;
0127:            protected String[] optionalMethodNames = null;
0128:            protected String[][] optionalParameterNames = null;
0129:            protected Class[][] optionalParameterTypes = null;
0130:            protected Class[][] optionalThrownExceptions = null;
0131:
0132:            private Method[] result = null; // null=uncooked
0133:
0134:            /**
0135:             * Equivalent to<pre>
0136:             * ScriptEvaluator se = new ScriptEvaluator();
0137:             * se.cook(script);</pre>
0138:             *
0139:             * @see #ScriptEvaluator()
0140:             * @see Cookable#cook(String)
0141:             */
0142:            public ScriptEvaluator(String script) throws CompileException,
0143:                    Parser.ParseException, Scanner.ScanException {
0144:                this .cook(script);
0145:            }
0146:
0147:            /**
0148:             * Equivalent to<pre>
0149:             * ScriptEvaluator se = new ScriptEvaluator();
0150:             * se.setReturnType(returnType);
0151:             * se.cook(script);</pre>
0152:             *
0153:             * @see #ScriptEvaluator()
0154:             * @see #setReturnType(Class)
0155:             * @see Cookable#cook(String)
0156:             */
0157:            public ScriptEvaluator(String script, Class returnType)
0158:                    throws CompileException, Parser.ParseException,
0159:                    Scanner.ScanException {
0160:                this .setReturnType(returnType);
0161:                this .cook(script);
0162:            }
0163:
0164:            /**
0165:             * Equivalent to<pre>
0166:             * ScriptEvaluator se = new ScriptEvaluator();
0167:             * se.setReturnType(returnType);
0168:             * se.setParameters(parameterNames, parameterTypes);
0169:             * se.cook(script);</pre>
0170:             *
0171:             * @see #ScriptEvaluator()
0172:             * @see #setReturnType(Class)
0173:             * @see #setParameters(String[], Class[])
0174:             * @see Cookable#cook(String)
0175:             */
0176:            public ScriptEvaluator(String script, Class returnType,
0177:                    String[] parameterNames, Class[] parameterTypes)
0178:                    throws CompileException, Parser.ParseException,
0179:                    Scanner.ScanException {
0180:                this .setReturnType(returnType);
0181:                this .setParameters(parameterNames, parameterTypes);
0182:                this .cook(script);
0183:            }
0184:
0185:            /**
0186:             * Equivalent to<pre>
0187:             * ScriptEvaluator se = new ScriptEvaluator();
0188:             * se.setReturnType(returnType);
0189:             * se.setParameters(parameterNames, parameterTypes);
0190:             * se.setThrownExceptions(thrownExceptions);
0191:             * se.cook(script);</pre>
0192:             *
0193:             * @see #ScriptEvaluator()
0194:             * @see #setReturnType(Class)
0195:             * @see #setParameters(String[], Class[])
0196:             * @see #setThrownExceptions(Class[])
0197:             * @see Cookable#cook(String)
0198:             */
0199:            public ScriptEvaluator(String script, Class returnType,
0200:                    String[] parameterNames, Class[] parameterTypes,
0201:                    Class[] thrownExceptions) throws CompileException,
0202:                    Parser.ParseException, Scanner.ScanException {
0203:                this .setReturnType(returnType);
0204:                this .setParameters(parameterNames, parameterTypes);
0205:                this .setThrownExceptions(thrownExceptions);
0206:                this .cook(script);
0207:            }
0208:
0209:            /**
0210:             * Equivalent to<pre>
0211:             * ScriptEvaluator se = new ScriptEvaluator();
0212:             * se.setReturnType(returnType);
0213:             * se.setParameters(parameterNames, parameterTypes);
0214:             * se.setThrownExceptions(thrownExceptions);
0215:             * se.setParentClassLoader(optionalParentClassLoader);
0216:             * se.cook(optionalFileName, is);</pre>
0217:             *
0218:             * @see #ScriptEvaluator()
0219:             * @see #setReturnType(Class)
0220:             * @see #setParameters(String[], Class[])
0221:             * @see #setThrownExceptions(Class[])
0222:             * @see SimpleCompiler#setParentClassLoader(ClassLoader)
0223:             * @see Cookable#cook(String, InputStream)
0224:             */
0225:            public ScriptEvaluator(String optionalFileName, InputStream is,
0226:                    Class returnType, String[] parameterNames,
0227:                    Class[] parameterTypes, Class[] thrownExceptions,
0228:                    ClassLoader optionalParentClassLoader // null = use current thread's context class loader
0229:            ) throws CompileException, Parser.ParseException,
0230:                    Scanner.ScanException, IOException {
0231:                this .setReturnType(returnType);
0232:                this .setParameters(parameterNames, parameterTypes);
0233:                this .setThrownExceptions(thrownExceptions);
0234:                this .setParentClassLoader(optionalParentClassLoader);
0235:                this .cook(optionalFileName, is);
0236:            }
0237:
0238:            /**
0239:             * Equivalent to<pre>
0240:             * ScriptEvaluator se = new ScriptEvaluator();
0241:             * se.setReturnType(returnType);
0242:             * se.setParameters(parameterNames, parameterTypes);
0243:             * se.setThrownExceptions(thrownExceptions);
0244:             * se.setParentClassLoader(optionalParentClassLoader);
0245:             * se.cook(reader);</pre>
0246:             *
0247:             * @see #ScriptEvaluator()
0248:             * @see #setReturnType(Class)
0249:             * @see #setParameters(String[], Class[])
0250:             * @see #setThrownExceptions(Class[])
0251:             * @see SimpleCompiler#setParentClassLoader(ClassLoader)
0252:             * @see Cookable#cook(String, Reader)
0253:             */
0254:            public ScriptEvaluator(String optionalFileName, Reader reader,
0255:                    Class returnType, String[] parameterNames,
0256:                    Class[] parameterTypes, Class[] thrownExceptions,
0257:                    ClassLoader optionalParentClassLoader // null = use current thread's context class loader
0258:            ) throws CompileException, Parser.ParseException,
0259:                    Scanner.ScanException, IOException {
0260:                this .setReturnType(returnType);
0261:                this .setParameters(parameterNames, parameterTypes);
0262:                this .setThrownExceptions(thrownExceptions);
0263:                this .setParentClassLoader(optionalParentClassLoader);
0264:                this .cook(optionalFileName, reader);
0265:            }
0266:
0267:            /**
0268:             * Equivalent to<pre>
0269:             * ScriptEvaluator se = new ScriptEvaluator();
0270:             * se.setReturnType(returnType);
0271:             * se.setParameters(parameterNames, parameterTypes);
0272:             * se.setThrownExceptions(thrownExceptions);
0273:             * se.setParentClassLoader(optionalParentClassLoader);
0274:             * se.cook(scanner);</pre>
0275:             *
0276:             * @see #ScriptEvaluator()
0277:             * @see #setReturnType(Class)
0278:             * @see #setParameters(String[], Class[])
0279:             * @see #setThrownExceptions(Class[])
0280:             * @see SimpleCompiler#setParentClassLoader(ClassLoader)
0281:             * @see Cookable#cook(Scanner)
0282:             */
0283:            public ScriptEvaluator(Scanner scanner, Class returnType,
0284:                    String[] parameterNames, Class[] parameterTypes,
0285:                    Class[] thrownExceptions,
0286:                    ClassLoader optionalParentClassLoader // null = use current thread's context class loader
0287:            ) throws CompileException, Parser.ParseException,
0288:                    Scanner.ScanException, IOException {
0289:                this .setReturnType(returnType);
0290:                this .setParameters(parameterNames, parameterTypes);
0291:                this .setThrownExceptions(thrownExceptions);
0292:                this .setParentClassLoader(optionalParentClassLoader);
0293:                this .cook(scanner);
0294:            }
0295:
0296:            /**
0297:             * Equivalent to<pre>
0298:             * ScriptEvaluator se = new ScriptEvaluator();
0299:             * se.setExtendedType(optionalExtendedType);
0300:             * se.setImplementedTypes(implementedTypes);
0301:             * se.setReturnType(returnType);
0302:             * se.setParameters(parameterNames, parameterTypes);
0303:             * se.setThrownExceptions(thrownExceptions);
0304:             * se.setParentClassLoader(optionalParentClassLoader);
0305:             * se.cook(scanner);</pre>
0306:             *
0307:             * @see #ScriptEvaluator()
0308:             * @see ClassBodyEvaluator#setExtendedType(Class)
0309:             * @see ClassBodyEvaluator#setImplementedTypes(Class[])
0310:             * @see #setReturnType(Class)
0311:             * @see #setParameters(String[], Class[])
0312:             * @see #setThrownExceptions(Class[])
0313:             * @see SimpleCompiler#setParentClassLoader(ClassLoader)
0314:             * @see Cookable#cook(Scanner)
0315:             */
0316:            public ScriptEvaluator(Scanner scanner, Class optionalExtendedType,
0317:                    Class[] implementedTypes, Class returnType,
0318:                    String[] parameterNames, Class[] parameterTypes,
0319:                    Class[] thrownExceptions,
0320:                    ClassLoader optionalParentClassLoader // null = use current thread's context class loader
0321:            ) throws CompileException, Parser.ParseException,
0322:                    Scanner.ScanException, IOException {
0323:                this .setExtendedType(optionalExtendedType);
0324:                this .setImplementedTypes(implementedTypes);
0325:                this .setReturnType(returnType);
0326:                this .setParameters(parameterNames, parameterTypes);
0327:                this .setThrownExceptions(thrownExceptions);
0328:                this .setParentClassLoader(optionalParentClassLoader);
0329:                this .cook(scanner);
0330:            }
0331:
0332:            /**
0333:             * Equivalent to<pre>
0334:             * ScriptEvaluator se = new ScriptEvaluator();
0335:             * se.setClassName(className);
0336:             * se.setExtendedType(optionalExtendedType);
0337:             * se.setImplementedTypes(implementedTypes);
0338:             * se.setStaticMethod(staticMethod);
0339:             * se.setReturnType(returnType);
0340:             * se.setMethodName(methodName);
0341:             * se.setParameters(parameterNames, parameterTypes);
0342:             * se.setThrownExceptions(thrownExceptions);
0343:             * se.setParentClassLoader(optionalParentClassLoader);
0344:             * se.cook(scanner);</pre>
0345:             *
0346:             * @see #ScriptEvaluator()
0347:             * @see ClassBodyEvaluator#setClassName(String)
0348:             * @see ClassBodyEvaluator#setExtendedType(Class)
0349:             * @see ClassBodyEvaluator#setImplementedTypes(Class[])
0350:             * @see #setStaticMethod(boolean)
0351:             * @see #setReturnType(Class)
0352:             * @see #setMethodName(String)
0353:             * @see #setParameters(String[], Class[])
0354:             * @see #setThrownExceptions(Class[])
0355:             * @see SimpleCompiler#setParentClassLoader(ClassLoader)
0356:             * @see Cookable#cook(Scanner)
0357:             */
0358:            public ScriptEvaluator(Scanner scanner, String className,
0359:                    Class optionalExtendedType, Class[] implementedTypes,
0360:                    boolean staticMethod, Class returnType, String methodName,
0361:                    String[] parameterNames, Class[] parameterTypes,
0362:                    Class[] thrownExceptions,
0363:                    ClassLoader optionalParentClassLoader // null = use current thread's context class loader
0364:            ) throws Scanner.ScanException, Parser.ParseException,
0365:                    CompileException, IOException {
0366:                this .setClassName(className);
0367:                this .setExtendedType(optionalExtendedType);
0368:                this .setImplementedTypes(implementedTypes);
0369:                this .setStaticMethod(staticMethod);
0370:                this .setReturnType(returnType);
0371:                this .setMethodName(methodName);
0372:                this .setParameters(parameterNames, parameterTypes);
0373:                this .setThrownExceptions(thrownExceptions);
0374:                this .setParentClassLoader(optionalParentClassLoader);
0375:                this .cook(scanner);
0376:            }
0377:
0378:            public ScriptEvaluator() {
0379:            }
0380:
0381:            /**
0382:             * Define whether the generated method should be STATIC or not. Defaults to <code>true</code>.
0383:             */
0384:            public void setStaticMethod(boolean staticMethod) {
0385:                this .setStaticMethod(new boolean[] { staticMethod });
0386:            }
0387:
0388:            /**
0389:             * Define the return type of the generated method. Defaults to <code>void.class</code>.
0390:             */
0391:            public void setReturnType(Class returnType) {
0392:                this .setReturnTypes(new Class[] { returnType });
0393:            }
0394:
0395:            /**
0396:             * Define the name of the generated method. Defaults to an unspecified name.
0397:             */
0398:            public void setMethodName(String methodName) {
0399:                this .setMethodNames(new String[] { methodName });
0400:            }
0401:
0402:            /**
0403:             * Define the names and types of the parameters of the generated method.
0404:             */
0405:            public void setParameters(String[] parameterNames,
0406:                    Class[] parameterTypes) {
0407:                this .setParameters(new String[][] { parameterNames },
0408:                        new Class[][] { parameterTypes });
0409:            }
0410:
0411:            /**
0412:             * Define the exceptions that the generated method may throw.
0413:             */
0414:            public void setThrownExceptions(Class[] thrownExceptions) {
0415:                this .setThrownExceptions(new Class[][] { thrownExceptions });
0416:            }
0417:
0418:            public final void cook(Scanner scanner) throws CompileException,
0419:                    Parser.ParseException, Scanner.ScanException, IOException {
0420:                this .cook(new Scanner[] { scanner });
0421:            }
0422:
0423:            /**
0424:             * Calls the generated method with concrete parameter values.
0425:             * <p>
0426:             * Each parameter value must have the same type as specified through
0427:             * the "parameterTypes" parameter of
0428:             * {@link #setParameters(String[], Class[])}.
0429:             * <p>
0430:             * Parameters of primitive type must passed with their wrapper class
0431:             * objects.
0432:             * <p>
0433:             * The object returned has the class as specified through
0434:             * {@link #setReturnType(Class)}.
0435:             * <p>
0436:             * This method is thread-safe.
0437:             *
0438:             * @param parameterValues The concrete parameter values.
0439:             */
0440:            public Object evaluate(Object[] parameterValues)
0441:                    throws InvocationTargetException {
0442:                return this .evaluate(0, parameterValues);
0443:            }
0444:
0445:            /**
0446:             * Returns the loaded {@link java.lang.reflect.Method}.
0447:             * <p>
0448:             * This method must only be called after {@link #cook(Scanner)}.
0449:             * <p>
0450:             * This method must not be called for instances of derived classes.
0451:             */
0452:            public Method getMethod() {
0453:                return this .getMethod(0);
0454:            }
0455:
0456:            /**
0457:             * Define whether the methods implementing each script should be STATIC or not. By default
0458:             * all scripts are compiled into STATIC methods.
0459:             */
0460:            public void setStaticMethod(boolean[] staticMethod) {
0461:                this .optionalStaticMethod = (boolean[]) staticMethod.clone();
0462:            }
0463:
0464:            /**
0465:             * Define the return types of the scripts. By default all scripts have VOID return type.
0466:             */
0467:            public void setReturnTypes(Class[] returnTypes) {
0468:                this .optionalReturnTypes = (Class[]) returnTypes.clone();
0469:            }
0470:
0471:            /**
0472:             * Define the names of the generated methods. By default the methods have distinct and
0473:             * implementation-specific names.
0474:             * <p>
0475:             * If two scripts have the same name, then they must have different parameter types
0476:             * (see {@link #setParameters(String[][], Class[][])}).
0477:             */
0478:            public void setMethodNames(String[] methodNames) {
0479:                this .optionalMethodNames = (String[]) methodNames.clone();
0480:            }
0481:
0482:            /**
0483:             * Define the names and types of the parameters of the generated methods.
0484:             */
0485:            public void setParameters(String[][] parameterNames,
0486:                    Class[][] parameterTypes) {
0487:                this .optionalParameterNames = (String[][]) parameterNames
0488:                        .clone();
0489:                this .optionalParameterTypes = (Class[][]) parameterTypes
0490:                        .clone();
0491:            }
0492:
0493:            /**
0494:             * Define the exceptions that the generated methods may throw.
0495:             */
0496:            public void setThrownExceptions(Class[][] thrownExceptions) {
0497:                this .optionalThrownExceptions = (Class[][]) thrownExceptions
0498:                        .clone();
0499:            }
0500:
0501:            /**
0502:             * Like {@link #cook(Scanner)}, but cooks a <i>set</i> of scripts into one class. Notice that
0503:             * if <i>any</i> of the scripts causes trouble, the entire compilation will fail. If you
0504:             * need to report <i>which</i> of the scripts causes the exception, you may want to use the
0505:             * <code>optionalFileName</code> argument of {@link Scanner#Scanner(String, Reader)} to
0506:             * distinguish between the individual token sources.
0507:             * <p>
0508:             * On a 2 GHz Intel Pentium Core Duo under Windows XP with an IBM 1.4.2 JDK, compiling
0509:             * 10000 expressions "a + b" (integer) takes about 4 seconds and 56 MB of main memory.
0510:             * The generated class file is 639203 bytes large.
0511:             * <p>
0512:             * The number and the complexity of the scripts is restricted by the
0513:             * <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88659">Limitations
0514:             * of the Java Virtual Machine</a>, where the most limiting factor is the 64K entries limit
0515:             * of the constant pool. Since every method with a distinct name requires one entry there,
0516:             * you can define at best 32K (very simple) scripts.
0517:             *
0518:             * If and only if the number of scanners is one, then that single script may contain leading
0519:             * IMPORT directives.
0520:             *
0521:             * @throws IllegalStateException if any of the preceeding <code>set...()</code> had an array size different from that of <code>scanners</code>
0522:             */
0523:            public final void cook(Scanner[] scanners) throws CompileException,
0524:                    Parser.ParseException, Scanner.ScanException, IOException {
0525:                if (scanners == null)
0526:                    throw new NullPointerException();
0527:
0528:                // The "dimension" of this ScriptEvaluator, i.e. how many scripts are cooked at the same
0529:                // time.
0530:                int count = scanners.length;
0531:
0532:                // Check array sizes.
0533:                if (this .optionalMethodNames != null
0534:                        && this .optionalMethodNames.length != count)
0535:                    throw new IllegalStateException("methodName");
0536:                if (this .optionalParameterNames != null
0537:                        && this .optionalParameterNames.length != count)
0538:                    throw new IllegalStateException("parameterNames");
0539:                if (this .optionalParameterTypes != null
0540:                        && this .optionalParameterTypes.length != count)
0541:                    throw new IllegalStateException("parameterTypes");
0542:                if (this .optionalReturnTypes != null
0543:                        && this .optionalReturnTypes.length != count)
0544:                    throw new IllegalStateException("returnTypes");
0545:                if (this .optionalStaticMethod != null
0546:                        && this .optionalStaticMethod.length != count)
0547:                    throw new IllegalStateException("staticMethod");
0548:                if (this .optionalThrownExceptions != null
0549:                        && this .optionalThrownExceptions.length != count)
0550:                    throw new IllegalStateException("thrownExceptions");
0551:
0552:                this .setUpClassLoaders();
0553:
0554:                // Create compilation unit.
0555:                Java.CompilationUnit compilationUnit = this 
0556:                        .makeCompilationUnit(count == 1 ? scanners[0] : null);
0557:
0558:                // Create class declaration.
0559:                Java.ClassDeclaration cd = this 
0560:                        .addPackageMemberClassDeclaration(scanners[0]
0561:                                .location(), compilationUnit);
0562:
0563:                // Determine method names.
0564:                String[] methodNames;
0565:                if (this .optionalMethodNames == null) {
0566:                    methodNames = new String[count];
0567:                    for (int i = 0; i < count; ++i)
0568:                        methodNames[i] = "eval" + i;
0569:                } else {
0570:                    methodNames = this .optionalMethodNames;
0571:                }
0572:
0573:                // Create methods with one block each.
0574:                for (int i = 0; i < count; ++i) {
0575:                    Scanner s = scanners[i];
0576:
0577:                    Java.Block block = this .makeBlock(i, scanners[i]);
0578:
0579:                    // Determine the following script properties AFTER the call to "makeBlock()",
0580:                    // because "makeBlock()" may modify these script properties on-the-fly.
0581:                    boolean staticMethod = this .optionalStaticMethod == null ? true
0582:                            : this .optionalStaticMethod[i];
0583:                    Class returnType = this .optionalReturnTypes == null ? this 
0584:                            .getDefaultReturnType()
0585:                            : this .optionalReturnTypes[i];
0586:                    String[] parameterNames = this .optionalParameterNames == null ? new String[0]
0587:                            : this .optionalParameterNames[i];
0588:                    Class[] parameterTypes = this .optionalParameterTypes == null ? new Class[0]
0589:                            : this .optionalParameterTypes[i];
0590:                    Class[] thrownExceptions = this .optionalThrownExceptions == null ? new Class[0]
0591:                            : this .optionalThrownExceptions[i];
0592:
0593:                    cd.addDeclaredMethod(this .makeMethodDeclaration(s
0594:                            .location(), // location
0595:                            staticMethod, // staticMethod
0596:                            returnType, // returnType
0597:                            methodNames[i], // methodName
0598:                            parameterTypes, // parameterTypes
0599:                            parameterNames, // parameterNames
0600:                            thrownExceptions, // thrownExceptions
0601:                            block // optionalBody
0602:                            ));
0603:                }
0604:
0605:                // Compile and load the compilation unit.
0606:                Class c = this .compileToClass(compilationUnit, // compilationUnit
0607:                        DebuggingInformation.DEFAULT_DEBUGGING_INFORMATION, // debuggingInformation
0608:                        this .className);
0609:
0610:                // Find the script methods by name.
0611:                this .result = new Method[count];
0612:                if (count <= 10) {
0613:                    for (int i = 0; i < count; ++i) {
0614:                        try {
0615:                            this .result[i] = c
0616:                                    .getDeclaredMethod(
0617:                                            methodNames[i],
0618:                                            this .optionalParameterTypes == null ? new Class[0]
0619:                                                    : this .optionalParameterTypes[i]);
0620:                        } catch (NoSuchMethodException ex) {
0621:                            throw new RuntimeException(
0622:                                    "SNO: Loaded class does not declare method \""
0623:                                            + methodNames[i] + "\"");
0624:                        }
0625:                    }
0626:                } else {
0627:                    class MethodWrapper {
0628:                        private final String name;
0629:                        private final Class[] parameterTypes;
0630:
0631:                        MethodWrapper(String name, Class[] parameterTypes) {
0632:                            this .name = name;
0633:                            this .parameterTypes = parameterTypes;
0634:                        }
0635:
0636:                        public boolean equals(Object o) {
0637:                            if (!(o instanceof  MethodWrapper))
0638:                                return false;
0639:                            MethodWrapper that = (MethodWrapper) o;
0640:                            if (!this .name.equals(that.name))
0641:                                return false;
0642:                            int cnt = this .parameterTypes.length;
0643:                            if (cnt != that.parameterTypes.length)
0644:                                return false;
0645:                            for (int i = 0; i < cnt; ++i) {
0646:                                if (!this .parameterTypes[i]
0647:                                        .equals(that.parameterTypes[i]))
0648:                                    return false;
0649:                            }
0650:                            return true;
0651:                        }
0652:
0653:                        public int hashCode() {
0654:                            int hc = this .name.hashCode();
0655:                            for (int i = 0; i < this .parameterTypes.length; ++i) {
0656:                                hc ^= this .parameterTypes[i].hashCode();
0657:                            }
0658:                            return hc;
0659:                        }
0660:                    }
0661:                    Method[] ma = c.getDeclaredMethods();
0662:                    Map dms = new HashMap(2 * count);
0663:                    for (int i = 0; i < ma.length; ++i) {
0664:                        Method m = ma[i];
0665:                        dms.put(new MethodWrapper(m.getName(), m
0666:                                .getParameterTypes()), m);
0667:                    }
0668:                    for (int i = 0; i < count; ++i) {
0669:                        Method m = (Method) dms
0670:                                .get(new MethodWrapper(
0671:                                        methodNames[i],
0672:                                        this .optionalParameterTypes == null ? new Class[0]
0673:                                                : this .optionalParameterTypes[i]));
0674:                        if (m == null)
0675:                            throw new RuntimeException(
0676:                                    "SNO: Loaded class does not declare method \""
0677:                                            + methodNames[i] + "\"");
0678:                        this .result[i] = m;
0679:                    }
0680:                }
0681:            }
0682:
0683:            public final void cook(Reader[] readers) throws CompileException,
0684:                    Parser.ParseException, Scanner.ScanException, IOException {
0685:                this .cook(new String[readers.length], readers);
0686:            }
0687:
0688:            /**
0689:             * @param optionalFileNames Used when reporting errors and warnings.
0690:             */
0691:            public final void cook(String[] optionalFileNames, Reader[] readers)
0692:                    throws CompileException, Parser.ParseException,
0693:                    Scanner.ScanException, IOException {
0694:                Scanner[] scanners = new Scanner[readers.length];
0695:                for (int i = 0; i < readers.length; ++i)
0696:                    scanners[i] = new Scanner(optionalFileNames[i], readers[i]);
0697:                this .cook(scanners);
0698:            }
0699:
0700:            /**
0701:             * Cook tokens from {@link java.lang.String}s.
0702:             */
0703:            public final void cook(String[] strings) throws CompileException,
0704:                    Parser.ParseException, Scanner.ScanException {
0705:                Reader[] readers = new Reader[strings.length];
0706:                for (int i = 0; i < strings.length; ++i)
0707:                    readers[i] = new StringReader(strings[i]);
0708:                try {
0709:                    this .cook(readers);
0710:                } catch (IOException ex) {
0711:                    throw new RuntimeException(
0712:                            "SNO: IOException despite StringReader");
0713:                }
0714:            }
0715:
0716:            protected Class getDefaultReturnType() {
0717:                return void.class;
0718:            }
0719:
0720:            /**
0721:             * Fill the given <code>block</code> by parsing statements until EOF and adding
0722:             * them to the block.
0723:             */
0724:            protected Java.Block makeBlock(int idx, Scanner scanner)
0725:                    throws ParseException, ScanException, IOException {
0726:                Java.Block block = new Java.Block(scanner.location());
0727:                Parser parser = new Parser(scanner);
0728:                while (!scanner.peek().isEOF()) {
0729:                    block.addStatement(parser.parseBlockStatement());
0730:                }
0731:
0732:                return block;
0733:            }
0734:
0735:            protected void compileToMethods(
0736:                    Java.CompilationUnit compilationUnit, String[] methodNames,
0737:                    Class[][] parameterTypes) throws CompileException {
0738:
0739:                // Compile and load the compilation unit.
0740:                Class c = this .compileToClass(compilationUnit, // compilationUnit
0741:                        DebuggingInformation.DEFAULT_DEBUGGING_INFORMATION, // debuggingInformation
0742:                        this .className);
0743:
0744:                // Find the script method by name.
0745:                this .result = new Method[methodNames.length];
0746:                for (int i = 0; i < this .result.length; ++i) {
0747:                    try {
0748:                        this .result[i] = c.getMethod(methodNames[i],
0749:                                parameterTypes[i]);
0750:                    } catch (NoSuchMethodException ex) {
0751:                        throw new RuntimeException(
0752:                                "SNO: Loaded class does not declare method \""
0753:                                        + this .optionalMethodNames[i] + "\"");
0754:                    }
0755:                }
0756:            }
0757:
0758:            /**
0759:             * To the given {@link Java.ClassDeclaration}, add
0760:             * <ul>
0761:             *   <li>A public method declaration with the given return type, name, parameter
0762:             *       names and values and thrown exceptions
0763:             *   <li>A block 
0764:             * </ul> 
0765:             *
0766:             * @param returnType Return type of the declared method
0767:             */
0768:            protected Java.MethodDeclarator makeMethodDeclaration(
0769:                    Location location, boolean staticMethod, Class returnType,
0770:                    String methodName, Class[] parameterTypes,
0771:                    String[] parameterNames, Class[] thrownExceptions,
0772:                    Java.Block optionalBody) {
0773:                if (parameterNames.length != parameterTypes.length)
0774:                    throw new RuntimeException(
0775:                            "Lengths of \"parameterNames\" ("
0776:                                    + parameterNames.length
0777:                                    + ") and \"parameterTypes\" ("
0778:                                    + parameterTypes.length + ") do not match");
0779:
0780:                Java.FunctionDeclarator.FormalParameter[] fps = new Java.FunctionDeclarator.FormalParameter[parameterNames.length];
0781:                for (int i = 0; i < fps.length; ++i) {
0782:                    fps[i] = new Java.FunctionDeclarator.FormalParameter(
0783:                            location, // location
0784:                            true, // finaL
0785:                            this .classToType(location, parameterTypes[i]), // type
0786:                            parameterNames[i] // name
0787:                    );
0788:                }
0789:
0790:                return new Java.MethodDeclarator(location, // location
0791:                        null, // optionalDocComment
0792:                        ( // modifiers
0793:                        staticMethod ? (short) (Mod.PUBLIC | Mod.STATIC)
0794:                                : (short) Mod.PUBLIC), this .classToType(
0795:                                location, returnType), // type
0796:                        methodName, // name
0797:                        fps, // formalParameters
0798:                        this .classesToTypes(location, thrownExceptions), // thrownExceptions
0799:                        optionalBody // optionalBody
0800:                );
0801:            }
0802:
0803:            /**
0804:             * Simplified version of
0805:             * {@link #createFastScriptEvaluator(Scanner, Class, String[], ClassLoader)}.
0806:             * 
0807:             * @param script Contains the sequence of script tokens
0808:             * @param interfaceToImplement Must declare exactly the one method that defines the expression's signature
0809:             * @param parameterNames The expression references the parameters through these names
0810:             * @return an object that implements the given interface and extends the <code>optionalExtendedType</code>
0811:             */
0812:            public static Object createFastScriptEvaluator(String script,
0813:                    Class interfaceToImplement, String[] parameterNames)
0814:                    throws CompileException, Parser.ParseException,
0815:                    Scanner.ScanException {
0816:                ScriptEvaluator se = new ScriptEvaluator();
0817:                return ScriptEvaluator.createFastEvaluator(se, script,
0818:                        parameterNames, interfaceToImplement);
0819:            }
0820:
0821:            /**
0822:             * If the parameter and return types of the expression are known at compile time,
0823:             * then a "fast" script evaluator can be instantiated through this method.
0824:             * <p>
0825:             * Script evaluation is faster than through {@link #evaluate(Object[])}, because
0826:             * it is not done through reflection but through direct method invocation.
0827:             * <p>
0828:             * Example:
0829:             * <pre>
0830:             * public interface Foo {
0831:             *     int bar(int a, int b);
0832:             * }
0833:             * ...
0834:             * Foo f = (Foo) ScriptEvaluator.createFastScriptEvaluator(
0835:             *     new Scanner(null, new StringReader("return a + b;")),
0836:             *     Foo.class,
0837:             *     new String[] { "a", "b" },
0838:             *     (ClassLoader) null          // Use current thread's context class loader
0839:             * );
0840:             * System.out.println("1 + 2 = " + f.bar(1, 2));
0841:             * </pre>
0842:             * Notice: The <code>interfaceToImplement</code> must either be declared <code>public</code>,
0843:             * or with package scope in the root package (i.e. "no" package).
0844:             * 
0845:             * @param scanner Source of script tokens
0846:             * @param interfaceToImplement Must declare exactly one method
0847:             * @param parameterNames
0848:             * @param optionalParentClassLoader
0849:             * @return an object that implements the given interface
0850:             */
0851:            public static Object createFastScriptEvaluator(Scanner scanner,
0852:                    Class interfaceToImplement, String[] parameterNames,
0853:                    ClassLoader optionalParentClassLoader)
0854:                    throws CompileException, Parser.ParseException,
0855:                    Scanner.ScanException, IOException {
0856:                ScriptEvaluator se = new ScriptEvaluator();
0857:                se.setParentClassLoader(optionalParentClassLoader);
0858:                return ScriptEvaluator.createFastEvaluator(se, scanner,
0859:                        parameterNames, interfaceToImplement);
0860:            }
0861:
0862:            /**
0863:             * Like {@link #createFastScriptEvaluator(Scanner, Class, String[], ClassLoader)},
0864:             * but gives you more control over the generated class (rarely needed in practice).
0865:             * <p> 
0866:             * Notice: The <code>interfaceToImplement</code> must either be declared <code>public</code>,
0867:             * or with package scope in the same package as <code>className</code>.
0868:             * 
0869:             * @param scanner                   Source of script tokens
0870:             * @param className                 Name of generated class
0871:             * @param optionalExtendedType      Class to extend
0872:             * @param interfaceToImplement      Must declare exactly the one method that defines the expression's signature
0873:             * @param parameterNames            The expression references the parameters through these names
0874:             * @param optionalParentClassLoader Used to load referenced classes, defaults to the current thread's "context class loader"
0875:             * @return an object that implements the given interface and extends the <code>optionalExtendedType</code>
0876:             */
0877:            public static Object createFastScriptEvaluator(Scanner scanner,
0878:                    String className, Class optionalExtendedType,
0879:                    Class interfaceToImplement, String[] parameterNames,
0880:                    ClassLoader optionalParentClassLoader)
0881:                    throws CompileException, Parser.ParseException,
0882:                    Scanner.ScanException, IOException {
0883:                ScriptEvaluator se = new ScriptEvaluator();
0884:                se.setClassName(className);
0885:                se.setExtendedType(optionalExtendedType);
0886:                se.setParentClassLoader(optionalParentClassLoader);
0887:                return ScriptEvaluator.createFastEvaluator(se, scanner,
0888:                        parameterNames, interfaceToImplement);
0889:            }
0890:
0891:            public static Object createFastScriptEvaluator(Scanner scanner,
0892:                    String[] optionalDefaultImports, String className,
0893:                    Class optionalExtendedType, Class interfaceToImplement,
0894:                    String[] parameterNames,
0895:                    ClassLoader optionalParentClassLoader)
0896:                    throws CompileException, Parser.ParseException,
0897:                    Scanner.ScanException, IOException {
0898:                ScriptEvaluator se = new ScriptEvaluator();
0899:                se.setClassName(className);
0900:                se.setExtendedType(optionalExtendedType);
0901:                se.setDefaultImports(optionalDefaultImports);
0902:                se.setParentClassLoader(optionalParentClassLoader);
0903:                return ScriptEvaluator.createFastEvaluator(se, scanner,
0904:                        parameterNames, interfaceToImplement);
0905:            }
0906:
0907:            public static Object createFastEvaluator(ScriptEvaluator se,
0908:                    String s, String[] parameterNames,
0909:                    Class interfaceToImplement) throws CompileException,
0910:                    Parser.ParseException, Scanner.ScanException {
0911:                try {
0912:                    return ScriptEvaluator.createFastEvaluator(se, new Scanner(
0913:                            null, new StringReader(s)), parameterNames,
0914:                            interfaceToImplement);
0915:                } catch (IOException ex) {
0916:                    throw new RuntimeException(
0917:                            "IOException despite StringReader");
0918:                }
0919:            }
0920:
0921:            /**
0922:             * Create and return an object that implements the exactly one method of the given
0923:             * <code>interfaceToImplement</code>.
0924:             *
0925:             * @param se A pre-configured {@link ScriptEvaluator} object
0926:             * @param scanner Source of tokens to read
0927:             * @param parameterNames The names of the parameters of the one abstract method of <code>interfaceToImplement</code>
0928:             * @param interfaceToImplement A type with exactly one abstract method
0929:             * @return an instance of the created {@link Object}
0930:             */
0931:            public static Object createFastEvaluator(ScriptEvaluator se,
0932:                    Scanner scanner, String[] parameterNames,
0933:                    Class interfaceToImplement) throws CompileException,
0934:                    Parser.ParseException, Scanner.ScanException, IOException {
0935:                if (!interfaceToImplement.isInterface())
0936:                    throw new RuntimeException("\"" + interfaceToImplement
0937:                            + "\" is not an interface");
0938:
0939:                Method[] methods = interfaceToImplement.getDeclaredMethods();
0940:                if (methods.length != 1)
0941:                    throw new RuntimeException("Interface \""
0942:                            + interfaceToImplement
0943:                            + "\" must declare exactly one method");
0944:                Method methodToImplement = methods[0];
0945:
0946:                se.setImplementedTypes(new Class[] { interfaceToImplement });
0947:                se.setStaticMethod(false);
0948:                se.setReturnType(methodToImplement.getReturnType());
0949:                se.setMethodName(methodToImplement.getName());
0950:                se.setParameters(parameterNames, methodToImplement
0951:                        .getParameterTypes());
0952:                se.setThrownExceptions(methodToImplement.getExceptionTypes());
0953:                se.cook(scanner);
0954:                Class c = se.getMethod().getDeclaringClass();
0955:                try {
0956:                    return c.newInstance();
0957:                } catch (InstantiationException e) {
0958:                    // SNO - Declared class is always non-abstract.
0959:                    throw new RuntimeException(e.toString());
0960:                } catch (IllegalAccessException e) {
0961:                    // SNO - interface methods are always PUBLIC.
0962:                    throw new RuntimeException(e.toString());
0963:                }
0964:            }
0965:
0966:            /**
0967:             * Calls the generated method with concrete parameter values.
0968:             * <p>
0969:             * Each parameter value must have the same type as specified through
0970:             * the "parameterTypes" parameter of
0971:             * {@link #setParameters(String[], Class[])}.
0972:             * <p>
0973:             * Parameters of primitive type must passed with their wrapper class
0974:             * objects.
0975:             * <p>
0976:             * The object returned has the class as specified through
0977:             * {@link #setReturnType(Class)}.
0978:             * <p>
0979:             * This method is thread-safe.
0980:             *
0981:             * @param idx The index of the script (0 ... <code>scripts.length - 1</code>)
0982:             * @param parameterValues The concrete parameter values.
0983:             */
0984:            public Object evaluate(int idx, Object[] parameterValues)
0985:                    throws InvocationTargetException {
0986:                if (this .result == null)
0987:                    throw new IllegalStateException(
0988:                            "Must only be called after \"cook()\"");
0989:                try {
0990:                    return this .result[idx].invoke(null, parameterValues);
0991:                } catch (IllegalAccessException ex) {
0992:                    throw new RuntimeException(ex.toString());
0993:                }
0994:            }
0995:
0996:            /**
0997:             * Returns the loaded {@link java.lang.reflect.Method}.
0998:             * <p>
0999:             * This method must only be called after {@link #cook(Scanner)}.
1000:             * <p>
1001:             * This method must not be called for instances of derived classes.
1002:             *
1003:             * @param idx The index of the script (0 ... <code>scripts.length - 1</code>)
1004:             */
1005:            public Method getMethod(int idx) {
1006:                if (this .result == null)
1007:                    throw new IllegalStateException(
1008:                            "Must only be called after \"cook()\"");
1009:                return this.result[idx];
1010:            }
1011:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.