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.lib.aggagent.session.IncrementFormat;
030: import org.cougaar.lib.aggagent.session.SubscriptionAccess;
031: import org.cougaar.lib.aggagent.session.UpdateDelta;
032: import org.python.core.PyFunction;
033: import org.python.core.PyObject;
034: import org.python.util.PythonInterpreter;
035:
036: /**
037: * An implementation of IncrementFormat that derives its functionality from
038: * a script written in the JPython language. A PythIncrementFormat is
039: * configured in two stages: one is to declare a function or class, and the
040: * other is to pass the function or an instance of the class to the
041: * controlling Java context.
042: * <br><br>
043: * The necessity of using a two-stage initialization procedure for both types
044: * of PythIncrementFormat implementations is due to JPython's resolute refusal
045: * to allow an expression to declare a new function or class (or, indeed, any
046: * multiline construct). One possibility is to use a "magic" function through
047: * which the Java and JPython contexts can communicate. For the sake of
048: * uniformity, this option is used here. The magic function is "instantiate",
049: * which the script should define in the global context as a no-arg function
050: * that returns either an IncrementFormat instance or a function designed to
051: * act as the "encode" method of an IncrementFormat.
052: * <br><br>
053: * This class implements the IncrementFormat interface, and can be
054: * instantiated by calling the constructor or a static factory method,
055: * formatFromScript().
056: */
057: public class PythIncrementFormat implements IncrementFormat {
058: // This is the JPython instruction evaluated to retrieve the product of the
059: // script. The script is responsible for providing the correct behavior to
060: // the named function.
061: private static String MAGIC_FUNCTION = "instantiate()";
062:
063: // IncrementFormat implementation that uses a JPython script as its encode
064: // method.
065: private static class Func implements IncrementFormat {
066: private PyFunction delegateFunction = null;
067:
068: public Func(PyFunction f) {
069: delegateFunction = f;
070: }
071:
072: public void encode(UpdateDelta out, SubscriptionAccess sacc) {
073: delegateFunction._jcall(new Object[] { out, sacc });
074: }
075: }
076:
077: // Each instance carrys a delegate IncrementFormat derived from a script
078: private IncrementFormat delegate = null;
079:
080: /**
081: * Create a PythIncrementFormat instance by using a script-generated
082: * IncrementFormat as a delegate.
083: * @param script the JPython script that defines the embodied functionality
084: */
085: public PythIncrementFormat(String script) {
086: delegate = formatFromScript(script);
087: }
088:
089: /**
090: * An implementation of the encode method of interface IncrementFormat. The
091: * function is actually delegated to a script-generated implementation,
092: * which is fabricated in the constructor.
093: *
094: * @param out an UpdateDelta to be returned to the client
095: * @param sacc the subscription data to be encoded
096: */
097: public void encode(UpdateDelta out, SubscriptionAccess sacc) {
098: delegate.encode(out, sacc);
099: }
100:
101: /**
102: * Create an IncrementFormat from a JPython script. There are two
103: * acceptable modes for the script. It must produce either a JPython
104: * subclass of Java interface IncrementFormat or a JPython function that
105: * behaves like the method IncrementFormat.encode (i.e., takes two
106: * arguments and treats them as an UpdateDelta and a SubscriptionAccess).
107: * Either way, the script is required to define the magic function
108: * "instantiate()" to provide the function or formatter instance to the Java
109: * context.
110: *
111: * @param script the executable script that declares classes and variables
112: * @return an IncrementFormat instance derived from the JPython scripts
113: */
114: public static IncrementFormat formatFromScript(String script) {
115: PythonInterpreter pi = new NoErrorPython();
116: if (script != null)
117: pi.exec(script);
118: PyObject product = pi.eval(MAGIC_FUNCTION);
119: if (product instanceof PyFunction) {
120: return new Func((PyFunction) product);
121: } else {
122: Object obj = product.__tojava__(IncrementFormat.class);
123: if (obj instanceof IncrementFormat)
124: return (IncrementFormat) obj;
125: }
126: throw new IllegalArgumentException(
127: "JPython script did not yield a function or an IncrementFormat");
128: }
129: }
|