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.util;
028:
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.HashMap;
032: import java.util.Iterator;
033: import java.util.Map;
034: import java.util.Stack;
035:
036: /** An extension of StackMachine which supports subroutines/functions
037: *
038: **/
039:
040: public class StackMachine extends StateMachine {
041: public StackMachine() {
042: super ();
043:
044: // psuedo-state for stack support
045: add(new SState("POP") {
046: public void invoke() {
047: Frame f = popFrame();
048: setVar("RESULT", f.getRetval());
049: transit(f.getReturnTag());
050: }
051: });
052:
053: add(new SState("ITERATE") {
054: public void invoke() {
055: Object[] args = (Object[]) getArgument();
056: Collection values = (Collection) args[0];
057: String subTag = (String) args[1];
058: setVar("it", values.iterator());
059: setVar("subTag", subTag);
060: transit("ITERATE1");
061: }
062: });
063: add(new SState("ITERATE1") {
064: public void invoke() {
065: Iterator it = (Iterator) getVar("it");
066: if (it.hasNext()) {
067: Object o = it.next();
068: String subTag = (String) getVar("subTag");
069: call(subTag, o, "ITERATE1");
070: } else {
071: callReturn(null);
072: }
073: }
074: });
075:
076: // initialize the stack (no argument, transit to ERROR if returned)
077: pushFrame(new Frame("ERROR", null));
078: }
079:
080: public static class Frame {
081: // next tag to go
082: private final String returnTag;
083:
084: public String getReturnTag() {
085: return returnTag;
086: }
087:
088: // argument object
089: private final Object argument;
090:
091: public Object getArgument() {
092: return argument;
093: }
094:
095: private Object retval = null;
096:
097: public Object getRetval() {
098: return retval;
099: }
100:
101: public void setRetval(Object o) {
102: retval = o;
103: }
104:
105: // frame variables
106: private final Map vars = new HashMap(5);
107:
108: public Object getVar(Object var) {
109: return vars.get(var);
110: }
111:
112: public void setVar(Object var, Object val) {
113: vars.put(var, val);
114: }
115:
116: public void unsetVar(Object var) {
117: vars.remove(var);
118: }
119:
120: public boolean varBound(Object var) {
121: return vars.containsKey(var);
122: }
123:
124: public Frame(String rtag, Object arg) {
125: returnTag = rtag;
126: argument = arg;
127: }
128: }
129:
130: private final Stack stack = new Stack();
131:
132: protected synchronized int stackSize() {
133: return stack.size();
134: }
135:
136: protected synchronized Frame popFrame() {
137: return (Frame) stack.pop();
138: }
139:
140: protected synchronized void pushFrame(Frame f) {
141: stack.push(f);
142: }
143:
144: /** get the current Frame object **/
145: protected synchronized Frame getFrame() {
146: Frame f = (Frame) stack.peek();
147: if (f == null) {
148: throw new IllegalStateException(
149: "No Stack Frame in current State");
150: }
151: return f;
152: }
153:
154: /** get the frame which is N elements above the current one.
155: * getFrame(0) == getFrame();
156: **/
157: protected synchronized Frame getFrame(int n) {
158: return (Frame) stack.elementAt((stack.size() - 1) - n);
159: }
160:
161: /** dynamic binding variable search **/
162: public synchronized Object searchStack(Object var) {
163: for (int l = stack.size() - 1, i = l; i >= 0; i--) {
164: Frame f = (Frame) stack.elementAt(i);
165: if (f.varBound(var)) {
166: return f.getVar(var);
167: }
168: }
169: return null;
170: }
171:
172: /** State object which adds accessors to Stack manipulation
173: * methods.
174: **/
175:
176: public static abstract class SState extends State {
177: protected SState(String s) {
178: super (s);
179: }
180:
181: protected StackMachine getSMachine() {
182: return (StackMachine) getMachine();
183: }
184:
185: protected Frame getFrame() {
186: return getSMachine().getFrame();
187: }
188:
189: protected Frame getFrame(int n) {
190: return getSMachine().getFrame(n);
191: }
192:
193: /** get the argument of the current Frame **/
194: protected Object getArgument() {
195: return getFrame().getArgument();
196: }
197:
198: /** Set the return value of the current Frame - this will
199: * become the value returned by getReturned() once
200: * the stack has popped.
201: * @note this is used on the subroutine side.
202: **/
203: protected void setResult(Object r) {
204: getFrame().setRetval(r);
205: }
206:
207: /** alias for getVar("RESULT");
208: * @note this is used on the caller side.
209: **/
210: protected Object getResult() {
211: return getVar("RESULT");
212: }
213:
214: /** Set the value of the variable in the current
215: * frame.
216: * alias for getFrame().setVar **/
217: protected void setVar(Object var, Object val) {
218: getFrame().setVar(var, val);
219: }
220:
221: /** get the value of the variable by searching through the stack
222: * until a value is found.
223: * If you want to avoid the search, use getFrame().getVar() instead.
224: */
225: protected Object getVar(Object var) {
226: synchronized (getSMachine()) {
227: return getSMachine().searchStack(var);
228: }
229: }
230:
231: /** copy the value in var1 into var2 **/
232: protected void dupVar(Object var1, Object var2) {
233: Frame f = getFrame();
234: f.setVar(var2, getVar(var1));
235: }
236:
237: /** call into a subroutine. The subroutine should end with a transit to
238: * the state "POP".
239: **/
240: protected void call(String tag, Object arg, String ret) {
241: synchronized (getSMachine()) {
242: getSMachine().pushFrame(new Frame(ret, arg));
243: transit(tag);
244: }
245: }
246:
247: /** Usual case of returning from a subroutine.
248: * equivalent to setResult() and transit("POP");
249: **/
250: protected void callReturn(Object result) {
251: synchronized (getSMachine()) {
252: setResult(result);
253: transit("POP");
254: }
255: }
256:
257: protected void iterate(Collection values, String subTag,
258: String nextTag) {
259: synchronized (getSMachine()) {
260: call("ITERATE", new Object[] { values, subTag },
261: nextTag);
262: }
263: }
264:
265: }
266: }
|