001/* An actor whose execution is specified by BeanShell Java code. 002 003Copyright (c) 2014 The Regents of the University of California. 004All rights reserved. 005Permission is hereby granted, without written agreement and without 006license or royalty fees, to use, copy, modify, and distribute this 007software and its documentation for any purpose, provided that the above 008copyright notice and the following two paragraphs appear in all copies 009of this software. 010 011IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015SUCH DAMAGE. 016 017THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022ENHANCEMENTS, OR MODIFICATIONS. 023 024*/ 025package org.kepler.scriptengine; 026 027import java.lang.reflect.Field; 028 029import javax.script.ScriptException; 030 031import ptolemy.kernel.CompositeEntity; 032import ptolemy.kernel.util.IllegalActionException; 033import ptolemy.kernel.util.NameDuplicationException; 034import ptolemy.kernel.util.Workspace; 035 036/** An actor whose execution is defined by BeanShell Java code. 037 * The code can be edited by double-clicking on the actor. 038 * <p>There are several differences between this actor and 039 * the Java actor. The Java actor requires: 040 * <ul> 041 * <li>A Java compiler.</li> 042 * <li>All the referenced classes must be imported.</li> 043 * <li>All ports and parameters must be explicitly declared 044 * as fields in the script.</li> 045 * </ul> 046 * There are several Java features not supported by this actor but 047 * allowed in the Java actor: 048 * <ul> 049 * <li>Annotations</li> 050 * <li>Generics</li> 051 * </ul> 052 * </p> 053 054 * <p>The following example defines an actor in BeanShell Java that 055 * computes factorials:</p> 056 * 057<pre> 0581. import ptolemy.data.IntToken; 0592. 0603. public class Actor { 0614. public void fire() { 0625. int val = ((IntToken)super.in.get(0)).intValue(); 0636. 0647. if(val < 0) { 0658. actor.error("Input must be non-negative"); 0669. } 06710. int total = 1; 06811. while(val > 1) { 06912. total *= val; 07013. val--; 07114. } 07215. out.broadcast(new IntToken(total)); 07316. } 07417.} 075</pre> 076 * 077 * <p>Line 1 imports the Java class used by the actor. Line 3 defines the 078 * Actor object. Lines 4-16 define the fire() method of the actor; this 079 * method is called each time this actor executes in the workflow. Line 5 080 * reads an integer from the input port called "input". A port or parameter 081 * called "foo" can be accessed in the Java code by simply using "foo". 082 * Lines 10-14 compute the factorial of the integer read from the port. 083 * Line 15 writes the result to the output port called "output". 084 * 085 * @author Daniel Crawl 086 * @version $Id: BeanShell.java 33884 2015-09-11 18:07:23Z crawl $ 087 */ 088public class BeanShell extends ScriptEngineActor { 089 090 public BeanShell(Workspace workspace) { 091 super(workspace); 092 } 093 094 public BeanShell(CompositeEntity container, String name) 095 throws IllegalActionException, NameDuplicationException { 096 super(container, name); 097 098 _invokeMethodWithReflection = true; 099 100 _editorFactory.syntaxStyle.setExpression("text/java"); 101 102 language.setToken("beanshell"); 103 104 script.setExpression("public class Actor {\n" + 105 " public void fire() {\n" + 106 " System.out.println(\"in fire\");\n" + 107 " }\n" + 108 "}\n"); 109 } 110 111 /////////////////////////////////////////////////////////////////// 112 //// protected methods //// 113 114 /** Put the given object to the actor instance in the script. 115 * @param name the name of the object to put. 116 * @param object the object to put. 117 */ 118 @Override 119 protected void _putObjectToActorInstance(String name, Object object) throws ScriptException { 120 121 // see if the actor class has this field 122 Field field = null; 123 try { 124 field = _actorObject.getClass().getField(name); 125 } catch(Exception e) { 126 // do nothing 127 } 128 129 if(field == null) { 130 // actor class does not have the field so put as global 131 String globalName = "_yyy_" + name; 132 _engine.put(globalName, object); 133 _engine.eval(object.getClass().getName() + " " + name + " = " + globalName); 134 } else { 135 try { 136 // set the field in the actor instance. 137 field.set(_actorObject, object); 138 } catch (Exception e) { 139 throw new ScriptException("Error setting port/parameter " + name + ": " + e.getMessage()); 140 } 141 } 142 } 143}