import java.math.BigInteger;
import edu.mit.ai.psg.traveler.*;
import java.lang.reflect.*;
import java.awt.*;
import java.awt.event.*;
import edu.mit.ai.psg.jexa.*;
import edu.mit.ai.psg.ui.outliner.*;
import edu.mit.ai.psg.ui.patches.CloseableFrame;
import javax.swing.JButton;
@author
class FutureFactorialTraced {
public static BigInteger factorial(final BigInteger n) {
CallRecord callRecord =
Trace.invokingStatic(factorialMethod, new Object[]{n});
if (1 == n.signum()) return (BigInteger) Trace.returning(callRecord, rangeProduct(ONE, n));
else
throw ((IllegalArgumentException)
Trace.throwing(callRecord,
new IllegalArgumentException("n < 1")));
}
static final BigInteger ONE = BigInteger.ONE;
static final BigInteger TWO = new BigInteger("2");
public static BigInteger rangeProduct(final BigInteger lo,
final BigInteger hi) {
CallRecord callRecord =
Trace.invokingStatic(rangeProductMethod, new Object[]{lo, hi});
if (lo.equals(hi)) return (BigInteger) Trace.returning(callRecord,
lo);
else if ((lo.add(BigInteger.ONE)).equals(hi))
return (BigInteger) Trace.returning(callRecord, lo.multiply(hi));
else {
final BigInteger mid = (lo.add(hi)).divide(TWO);
Trace.doing(new StringRecord("mid = "+mid));
FutureTraced loProd = (new FutureTraced() { { start(); }
public Object compute() {
return rangeProduct(lo, mid); }});
FutureTraced hiProd = (new FutureTraced() { { start(); }
public Object compute() {
return rangeProduct(mid.add(ONE), hi); }});
return
((BigInteger)
Trace.returning
(callRecord,
((BigInteger)loProd.value()).multiply((BigInteger)hiProd.value())));
}
}
static Method factorialMethod =
Trace.getMethod(FutureFactorialTraced.class,
"factorial", new Class[]{BigInteger.class});
static Method rangeProductMethod =
Trace.getMethod(FutureFactorialTraced.class,
"rangeProduct", new Class[]{BigInteger.class,
BigInteger.class});
}
abstract class FutureTraced
implements Runnable, Cloneable, FutureFactorialApplet.CloneablePublic
{
private State myState = UNINITIALIZED;
private Object myValue = null;
private static class State {
private String stateName;
State(String stateName) { this.stateName = stateName; }
public String toString() { return stateName; }
}
private static final
State UNINITIALIZED = new State("Uninitialized");
private static final
State INITIALIZED_AND_STARTED= new State("Initialized and started");
private static final
State COMPLETED_RETURN = new State("Completed with return");
private static final
State COMPLETED_THROW = new State("Completed with throw");
FutureTraced() {}
public Object clone() throws CloneNotSupportedException {
return super.clone(); }
@throwsIllegalStateException
public synchronized void start() {
CallRecord callRecord =
(traceLev == 0 ? null : Trace.receiving(this, startMethod, null));
if (myState == UNINITIALIZED) {
Thread thread = new Thread(this);
Trace.starting(thread);
thread.start();
myState = INITIALIZED_AND_STARTED;
if (traceLev != 0) Trace.returningVoid(callRecord);
return;
} else {
throw ((IllegalStateException)
Trace.throwing
(callRecord, new IllegalStateException("Already started.")));
}
}
protected abstract Object compute();
public synchronized void run() {
CallRecord callRecord =
(traceLev == 0 ? null : Trace.receiving(this, runMethod, null));
while (myState == UNINITIALIZED)
try { this.wait(); } catch (InterruptedException e) {}
if (myState == INITIALIZED_AND_STARTED) {
try {
myValue = compute();
myState = COMPLETED_RETURN;
} catch(Throwable t) {
myValue = t;
myState = COMPLETED_THROW;
}
this.notifyAll();
}
if (traceLev != 0) Trace.returningVoid(callRecord);
}
@throwsError{@link #compute()}@throwsRuntimeException{@link #compute()}
public synchronized Object value() {
CallRecord valueRecord = (traceLev == 0 ? null : Trace.receiving(this,valueMethod,null));
while (! (myState == COMPLETED_RETURN || myState == COMPLETED_THROW)) {
CallRecord waitRecord = (traceLev == 0 ? null :
Trace.invoking(this,waitMethod,null));
try {
this.wait();
if (traceLev != 0) Trace.returningVoid(waitRecord);
}
catch (InterruptedException e) {
Error error = new Error(e.toString());
throw (traceLev == 0 ? error :
(Error) Trace.throwing(waitRecord, error));
}
}
if (myState == COMPLETED_RETURN)
return (traceLev == 0 ? myValue :
Trace.returning(valueRecord, myValue));
else { Throwable thrown = (traceLev == 0? (Throwable) myValue :
Trace.throwing(valueRecord,
(Throwable) myValue));
if (dbgLev> 0) thrown.printStackTrace();
if (thrown instanceof Error) throw (Error) thrown;
else throw (RuntimeException) thrown;
}
}
public String toString() {
return "Future(state="+myState+", value="+myValue+")";}
static final Method startMethod =
Trace.getMethod(FutureTraced.class, "start", null);
static final Method runMethod =
Trace.getMethod(FutureTraced.class, "run", null);
static final Method valueMethod =
Trace.getMethod(FutureTraced.class, "value", null);
static final Method waitMethod =
Trace.getMethod(FutureTraced.class, "wait", null);
public static int traceLev = 1;
public static int dbgLev = 1;
}
public class FutureFactorialApplet extends JexaApplet {
public static void main(String[] args) {
TravelerOutliner.ensureInitialized();
if (args.length > 0) initialParameter = args[0];
Frame frame = new FutureFactorialApplet().initFrameApplet();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }});
}
static String initialParameter = "10";
public static ActivityRecord run(String parameter) {
ActivityRecord record =
Trace.entering(new StringRecord(FutureTraced.traceLev == 0 ?
"// Not recording Future activity:" :
"// Recording Future activity:"));
BigInteger result =
FutureFactorialTraced.factorial(new BigInteger(parameter));
System.out.println(result);
return record;
}
public String getAppletTitle() { return "Traveler: Future Factorial"; }
public Object getObjectToExamine() {
return null;
}
public void initPanelInPlaceApplet() {
TravelerOutliner.ensureInitialized();
super.initPanelInPlaceApplet();
Panel headPanel = (Panel) getComponent(0);
Panel jexaPanel = (Panel) getComponent(1);
headPanel.add(makeParamPanel(jexaPanel), BorderLayout.SOUTH);
}
public Frame initFrameApplet() {
TravelerOutliner.ensureInitialized();
Frame frame = new CloseableFrame(getAppletTitle());
Panel jexaPanel = new Panel();
OutlineNode node =
Outliner.outlineMaker.makeOutlineNode(getObjectToExamine());
Outliner.outlineMaker.initializePane(jexaPanel, node);
frame.add(makeParamPanel(jexaPanel), BorderLayout.NORTH);
frame.add(jexaPanel, BorderLayout.CENTER);
frame.setBounds(60, 28, 580, 300);
frame.show();
return frame;
}
public Panel makeParamPanel(final Container jexaPane) {
Panel paramPanel = new Panel(new FlowLayout(FlowLayout.CENTER, 0, 0));
paramPanel.setBackground(SystemColor.control);
paramPanel.add(new Label("factorial("));
final TextField paramField = new TextField(initialParameter, 2);
paramPanel.add(paramField);
paramPanel.add(new Label(")"));
final Checkbox recordFutureCheckBox =
new Checkbox("Record calls on Futures also (more complex)");
final Button paramButton = new Button("Go");
paramButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String param = paramField.getText().trim();
if ("".equals(param)) paramField.setText(param = initialParameter);
FutureTraced.traceLev = recordFutureCheckBox.getState() ? 1 : 0;
ActivityRecord record = run(param);
OutlineNode node = Outliner.outlineMaker.makeOutlineNode(record);
jexaPane.invalidate();
Outliner.outlineMaker.initializePane(jexaPane, node);
jexaPane.validate();
}});
paramPanel.add(paramButton);
paramPanel.add(new Label(" ")); paramPanel.add(recordFutureCheckBox);
return paramPanel;
}
public interface CloneablePublic {
public Object clone() throws CloneNotSupportedException;
}
}