001: /*
002: * <copyright>
003: *
004: * Copyright 2003-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.lib.aggagent.script;
028:
029: import org.cougaar.util.UnaryPredicate;
030: import org.python.core.PyFunction;
031: import org.python.core.PyInteger;
032: import org.python.core.PyObject;
033: import org.python.util.PythonInterpreter;
034:
035: /**
036: * An implementation of UnaryPredicate that derives its functionality from
037: * a script written in the JPython language. A PythUnaryPredicate is
038: * configured in two stages: one is to declare a function or class, and the
039: * other is to pass the function or an instance of the class to the
040: * controlling Java context.
041: * <br><br>
042: * The necessity of using a two-stage initialization procedure for both types
043: * of PythUnaryPredicate implementations is due to JPython's resolute refusal
044: * to allow an expression to declare a new function or class (or, indeed, any
045: * multiline construct). One possibility is to use a "magic" function through
046: * which the Java and JPython contexts can communicate. For the sake of
047: * uniformity, this option is used here. The magic function is "instantiate",
048: * which the script should define in the global context as a no-arg function
049: * that returns either a UnaryPredicate instance or a function designed to act
050: * as the "execute" method of a UnaryPredicate.
051: * <br><br>
052: * This class implements the UnaryPredicate interface, and can be instantiated
053: * by calling the constructor or a static factory method,
054: * predicateFromScript().
055: */
056: public class PythUnaryPredicate implements UnaryPredicate {
057: // This is the JPython instruction evaluated to retrieve the product of the
058: // script. The script is responsible for providing the correct behavior to
059: // the named function.
060: private static String MAGIC_FUNCTION = "instantiate()";
061:
062: // Implementation of a UnaryPredicate that uses a JPython function as a
063: // delegate for the execute(Object) method. Arguments are coerced into the
064: // JPython context, where the function is evaluated, and the return type is
065: // interpreted as a boolean.
066: private static class Func implements UnaryPredicate {
067: private PyFunction delegateFunction = null;
068:
069: // Interpret the value returned by a JPython function call as a Java
070: // boolean. PyIntegers whose value is not zero are interpreted as "true",
071: // while anything else is presumed to represent "false".
072: private static boolean booleanVal(PyObject p) {
073: if (p instanceof PyInteger)
074: return ((PyInteger) p).getValue() != 0;
075: return false;
076: }
077:
078: public Func(PyFunction f) {
079: delegateFunction = f;
080: }
081:
082: public boolean execute(Object o) {
083: return booleanVal(delegateFunction
084: ._jcall(new Object[] { o }));
085: }
086: }
087:
088: // Each instance carrys a delegate UnaryPredicate derived from a script
089: private UnaryPredicate delegate = null;
090:
091: /**
092: * Create a PythUnaryPredicate instance by using a script-generated
093: * UnaryPredicate as a delegate.
094: * @param script the JPython script that defines the embodied functionality
095: */
096: public PythUnaryPredicate(String script) {
097: delegate = predicateFromScript(script);
098: }
099:
100: /**
101: * An implementation of the execute method of interface UnaryPredicate. The
102: * function is actually delegated to a script-generated implementation,
103: * which is fabricated in the constructor.
104: *
105: * @param o an object to be tested
106: * @return true if and only if the object matches the predicate
107: */
108: public boolean execute(Object o) {
109: return delegate.execute(o);
110: }
111:
112: /**
113: * Create a UnaryPredicate from a JPython script. There are two acceptable
114: * modes for the script. Either it must produce a JPython subclass of Java
115: * interface UnaryPredicate, or it must produce a JPython function that
116: * behaves like the method UnaryPredicate.execute (i.e., takes one argument
117: * and returns a JPython-style boolean result (which is really a number
118: * where zero denotes "false" and any other value denotes "true")). Either
119: * way, the script is required to define the magic function "instantiate()"
120: * to provide the function or predicate instance to the Java context.
121: *
122: * @param script the executable script that declares classes and variables
123: * @return a UnaryPredicate instance derived from the JPython scripts
124: */
125: public static UnaryPredicate predicateFromScript(String script) {
126: PythonInterpreter pi = new NoErrorPython();
127: if (script != null)
128: pi.exec(script);
129: PyObject product = pi.eval(MAGIC_FUNCTION);
130: if (product instanceof PyFunction) {
131: return new Func((PyFunction) product);
132: } else {
133: Object obj = product.__tojava__(UnaryPredicate.class);
134: if (obj instanceof UnaryPredicate)
135: return (UnaryPredicate) obj;
136: }
137: throw new IllegalArgumentException(
138: "JPython script did not yield a function or a UnaryPredicate");
139: }
140:
141: // - - - - - - - Testing code below this point - - - - - - - - - - - - - - - - -
142:
143: private static String PREDICATE_FOR_PUP = "from org.cougaar.util import UnaryPredicate\n"
144: + "class PupFind (UnaryPredicate):\n"
145: + " def execute (self, obj):\n"
146: + " return isinstance(obj, UnaryPredicate)\n"
147: + "def instantiate ():\n" + " return PupFind()\n";
148:
149: private static String FUNCTION_FOR_PUP = "from org.cougaar.util import UnaryPredicate\n"
150: + "def execute (obj):\n"
151: + " return isinstance(obj, UnaryPredicate)\n"
152: + "def instantiate ():\n" + " return execute\n";
153:
154: public static void main(String[] argv) {
155: UnaryPredicate inst = new PythUnaryPredicate(PREDICATE_FOR_PUP);
156: UnaryPredicate func = new PythUnaryPredicate(FUNCTION_FOR_PUP);
157: Object o = new Object();
158: System.out.println("Trial 1: " + inst.execute(inst) + " "
159: + func.execute(inst));
160: System.out.println("Trial 2: " + inst.execute(func) + " "
161: + func.execute(func));
162: System.out.println("Trial 3: " + inst.execute(o) + " "
163: + func.execute(o));
164: }
165: }
|