2 * Created on Sep 11, 2003
7 import isac.util.CalcChanged;
8 import isac.util.CalcChangedEvent;
9 import isac.util.NotInSpecificationPhaseException;
10 import isac.util.StartSolvingException;
11 import isac.util.formulae.CalcHead;
12 import isac.util.formulae.CalcFormula;
13 import isac.util.formulae.CalcHeadCompoundID;
14 import isac.util.formulae.Position;
15 import isac.util.interfaces.ICalcIterator;
16 import isac.util.interfaces.IToCalc;
17 import isac.util.interfaces.IToUser;
18 import isac.util.tactics.Tactic;
19 import isac.wsdialog.DialogGuide;
21 import java.io.Serializable;
22 import java.rmi.RemoteException;
23 import java.util.Iterator;
24 import java.util.Vector;
26 import org.apache.log4j.Logger;
29 * A CalcTree represents a Calculation: It is a tree which consists of one
30 * CalcHead at the top and abitrarily many Formulas and SubCalculations (with
31 * separate CalcHeads). This is the main interface between the Bridge and the
32 * Dialog. The CalcTree calls methods of the Math Engine, which in turn are
33 * delegated to the BridgeRMI object on the other side of the RMI connection
34 * ??????WN0409. The communication with the SML Kernel is completly hided from
35 * the Dialog and the Frontend.
37 * @author Richard Gradischnegg
40 public class CalcTree implements IToCalc, Serializable {
44 private Vector listeners_;
46 private MathEngine mathEngine_;
48 private ICalcIterator hot_spot_;//WN040924 ..delete: control hotSpot --> DG
50 private IBridgeRMI bridgeRMI_;//WN040924 added for completeCalcHead & Co.
52 static Logger logger_ = Logger.getLogger(CalcTree.class.getName());
55 * Start a new calculation. In case of failure, the constructor may change
56 * the formalization object to hint at incomplete or contradictory
57 * specifications. <br>
58 * Only complete calcHeads should be passed. <br>
59 * Check every CalcHead for completeness (with the static method
60 * checkcalcHead() before constructing a CalcTree ..TODO WN040824 shift to
63 * @param identification
64 * for the CalcTree as delivered by the SML-kernel
66 CalcTree(MathEngine me, int id) {
68 this.mathEngine_ = me;
69 this.bridgeRMI_ = me.getBridgeRMI();//WN040924
70 listeners_ = new Vector();
74 * Attach another dialog to the existing calculation tree.
77 * The new Dialog to be attached to this CalcTree
79 public void attach(DialogGuide dg) {
84 * Get a new iterator referencing the root element of the calculation tree.
86 * The functionality for navigating the calculation is implemented in the
87 * CalcIterator object.
89 * @return new instance of CalcIterator
91 public ICalcIterator iterator() {
92 return new CalcIterator(this);
96 * Makes the passed formula the active formula, i.e. the formula the next
97 * tactic is applied to.
99 * @param newActiveFormula
101 public void moveActiveFormula(ICalcIterator cit) {
103 Position p = mathEngine_.moveActiveFormula(id_, cit.getPosition());
104 // if (p == null)//WN0412 message ?!
108 } catch (RemoteException e) {
109 // TODO Auto-generated catch block
115 * @see isac.util.interfaces.IToCalc#startSolving()
117 public void startSolving() throws Exception {
118 Tactic tac = this.fetchProposedTactic();
119 if (tac.getName().compareTo("Apply_Method") == 0)
120 this.autoCalculate(IToCalc.SCOPE_CALCULATION, 1);
122 new StartSolvingException (tac);
126 * @see isac.util.interfaces.IToCalc#modifyCalcHead(isac.util.formulae.CalcHead)
128 public void modifyCalcHead(CalcHead calcHead) {
129 logger_.fatal(" DG->BR: modifyCalcHead(" + calcHead.toSMLString());
130 CalcHead newCalcHead = null;
132 //WN040924 newCalcHead = bridgeRMI.modifyCalcHead(calcHead);
133 bridgeRMI_.modifyCalcHead(calcHead);
134 //WN040924 calcHead.fillValuesfrom(newCalcHead);
135 } catch (RemoteException e) {
141 * @see isac.util.interfaces.IToCalc#completeCalcHead(isac.util.formulae.CalcHead)
143 public void completeCalcHead() {
144 logger_.fatal(" DG->BR: completeCalcHead()");
146 //WN040924 newCalcHead = bridgeRMI.completeCalcHead(calcHead);
147 bridgeRMI_.completeCalcHead(this.id_);
148 //WN040924 calcHead.fillValuesfrom(newCalcHead);
149 } catch (RemoteException e) {
155 * @see isac.util.interfaces.IToCalc#completeCalcHead(isac.util.formulae.CalcHead,
158 * eventually updated by the user
159 * @param completeItem
160 * requested by the DialogGuide
162 * WN040924 copied from MathEngine
165 public void completeCalcHead(CalcHead calcHead, int completeItem) {
166 // CalcHead newCalcHead;
168 // //WN040924 newCalcHead = bridgeRMI.completeCalcHead(calcHead,
170 // bridgeRMI_.completeCalcHead(this.id_, calcHead, completeItem);
171 // //WN040924 calcHead.fillValuesfrom(newCalcHead);
172 // //TODO: Remove the following line!!
173 // calcHead.setCalcHeadStatus(CalcHead.MODEL_ITEM_CORRECT);
175 // } catch (RemoteException e) {
176 // e.printStackTrace();
181 * Calculate the next n steps starting from the active formula. The Tactic
182 * to be applied in this step may be preset by setNextTactic
185 * The scope parameter can have following values:
187 * <li>Stay in the current subproblem
188 * <li>Stay in the current subcalculation (e.g. repetitions)
189 * <li>Stay in the current calculation as a whole.
191 * Constants for this scopes are found in the IToCalc class
193 * Specifies the count of steps to be autocalculated. Passing 0
194 * for nSteps will calculate until reaching a final result.
195 * @return The method returns an unique id to identify the request when
196 * notifying about updates in the tree.
198 * WN0504 see differences to this method completely done by RG !
200 public int autoCalculate(int scope, int nSteps) {
201 logger_.fatal(" DG->BR: autoCalculate(" + scope + ", " + nSteps + ")");
203 int transactionID = -1;
205 cc = mathEngine_.autoCalculate(this.id_, scope, nSteps);
207 hot_spot_ = new CalcIterator(this, cc.getLastGenerated());
208 transactionID = generateTransactionID();
209 informListeners(new CalcIterator(this, cc.getLastUnchanged()),
210 new CalcIterator(this, cc.getLastDeleted()),
211 new CalcIterator(this, cc.getLastGenerated()),
214 } catch (RemoteException e) {
217 return transactionID;
221 * Tries to replaces the active formula in the calculation tree by the
222 * passed formula. This could fail if no valid derivation from the preceding
223 * formula to the (new) active formula can be found.
225 * Parts of the calculation after the replaced formula are likely to become
226 * invalid, listeners will be informed of this with the update message,
227 * which contains the last unchanged formula.
230 * @return The method will return 0 on success or a nonzero value indicating
231 * the status otherwise.
233 public int replaceFormula(CalcFormula f) throws RemoteException {
234 logger_.fatal(" DG->BR: replaceFormula(" + f.toSMLString() + ")");
236 int transactionID = -1;
238 cc = mathEngine_.replaceFormula(this.id_, f);
240 hot_spot_ = new CalcIterator(this, cc.getLastGenerated());
241 transactionID = generateTransactionID();
242 informListeners(new CalcIterator(this, cc.getLastUnchanged()),
243 new CalcIterator(this, cc.getLastDeleted()),
244 new CalcIterator(this, cc.getLastGenerated()),
247 } catch (RemoteException e) {
254 * Tries to append the passed formula after the active formula. This could
255 * fail if no valid derivation from the preceding formula to the (new)
256 * active formula can be found. The method will fail as well if the active
257 * formula is not the last formula in the (sub)calculation. Parts of the
258 * calculation might become invalid.
261 * @return The method will return 0 on success or a nonzero value indicating
262 * the status otherwise.
264 public int appendFormula(CalcFormula f) throws RemoteException {
265 logger_.fatal(" DG->BR: appendFormula(" + f.toSMLString() + ")");
267 int transactionID = -1;
269 cc = mathEngine_.appendFormula(this.id_, f);
271 hot_spot_ = new CalcIterator(this, cc.getLastGenerated());
272 transactionID = generateTransactionID();
273 informListeners(new CalcIterator(this, cc.getLastUnchanged()),
274 new CalcIterator(this, cc.getLastDeleted()),
275 new CalcIterator(this, cc.getLastGenerated()),
278 } catch (RemoteException e) {
285 * @see isac.util.interfaces.IToCalc#intermediateSteps()
287 public int intermediateSteps(ICalcIterator ci) throws RemoteException {
288 logger_.fatal(" DG->BR: intermediateSteps(" + ci.toSMLString() + ")");
290 int transactionID = -1;
292 cc = mathEngine_.intermediateSteps(this.id_, ci);
294 transactionID = generateTransactionID();
295 informListeners(new CalcIterator(this, cc.getLastUnchanged()),
296 new CalcIterator(this, cc.getLastDeleted()),
297 new CalcIterator(this, cc.getLastGenerated()),
300 } catch (RemoteException e) {
307 * Set a tactic for usage by autocalculate.
310 * the Tactic to be used in the the next step
311 * @return The return value indicates success, failure or probable success
314 public int setNextTactic(Tactic tactic) {
315 logger_.fatal(" DG->BR: setNextTactic(" + tactic.toSMLString() + ")");
318 result = mathEngine_.setNextTactic(this.id_, tactic);
320 hot_spot_.moveDown(); // move to the new formula/calcHead
322 informListeners((ICalcIterator) hot_spot_.clone(),
323 // FIXXXME: nothing changed, but if outcommented: subpbl shows
324 // Add_Given etc. ... discuss with LK !
325 (ICalcIterator) hot_spot_.clone(),
326 (ICalcIterator) hot_spot_.clone(),
327 generateTransactionID());
329 } catch (RemoteException e) {
330 // TODO Auto-generated catch block
336 // public int setNextTactic(Tactic tactic) {
337 // logger_.fatal(" DG->BR: setNextTactic(" + tactic.toSMLString() + ")");
341 // result = mathEngine_.setNextTactic(this.id_, tactic);
342 // //^^^^ should be CalcChanged !
343 // if (result == 0) {
344 // //hack before @@@ autoCalculate --->
345 // // isac.wsdialog.DialogGuide#notifyUserAction
346 // //works only if nothing is deleted by use in <Next Step>
347 // it = (ICalcIterator) hot_spot_.clone();
348 // hot_spot_.moveDown();
349 // informListeners((ICalcIterator) it, it,//thus deleted nodes
350 // // are not reported !!!
351 // (ICalcIterator) hot_spot_.clone(),
352 // generateTransactionID());
354 // } catch (RemoteException e) {
355 // // TODO Auto-generated catch block
356 // e.printStackTrace();
362 * Retrieve the tactic proposed by the SML-Kernel for the next step in the
365 * @return proposed tactic. Can be null, if the kernel does not know what to
366 * do next, or if the end of the calculation is reached
368 public Tactic fetchProposedTactic() {
369 logger_.fatal(" DG->BR: fetchProposedTactic()");
371 Tactic tac = mathEngine_.fetchProposedTactic(this.id_);
372 logger_.fatal(" DG<-BR: fetchProposedTactic <- "
373 + tac.toSMLString());
375 } catch (RemoteException e) {
376 // TODO Auto-generated catch block
379 logger_.fatal(" DG<-BR: fetchProposedTactic <- NULL helpless");
384 // * Get a list of tactics applicable to the active formula.
387 // * The filter parameter selects the scope of search for
388 // * applicable tactics: all tactics / all tactics from the current
389 // * theory / all tactics from the (calculation) method being
391 // * @return Array with applyable tactics
393 // public Tactic[] fetchApplicableTactics(int scope) {
394 // logger_.fatal(" DG->BR: fetchApplicableTactics(" + scope + ")");
395 // Tactic[] result = null;
397 // // result = mathEngine_.fetchAppliableTactics(this.id_, scope);
398 // // } catch (RemoteException e) {
399 // // // TODO Auto-generated catch block
400 // // e.printStackTrace();
406 * Add a Listener to this CalcTree. Listeners will be informed about any
407 * changes in the CalcTree.
410 * the new Listener, has to implement the interface IToUser
411 * @return true, if the listener has been added successfully
413 public boolean addDataChangeListener(IToUser listener) {
414 logger_.fatal(" DG->BR: addDataChangeListener(" + listener + ")");
415 if (listeners_.contains(listener)) {
418 listeners_.add(listener);
424 * Retrieve the active formula in a CalcTree. This is the formula form where
425 * the calculation will continue.
427 * @return Iterator that marks the currently active formula
429 public ICalcIterator getActiveFormula() {
430 logger_.fatal(" DG<>BR: getActiveFormula <- "
431 + hot_spot_.toSMLString());
432 return (ICalcIterator) hot_spot_.clone();
436 * Destruct this CalcTree: the sml-Representation of the CalcTree is
437 * disposed, the id can be used for a new CalcTree
439 * @return boolean value: success of operation (complete/failed) TODO
440 * WN040824 call mathEngine.destruct when WS is closed TODO WN040824
441 * call mathEngine.destruct when session is closed
443 public boolean destruct() {
445 return mathEngine_.destruct(this.id_);
446 } catch (RemoteException e) {
447 // TODO Auto-generated catch block
453 // send an update event to the registered listeners
454 private void informListeners(ICalcIterator lastUnchangedFormula,
455 ICalcIterator lastDeletedFormula,
456 ICalcIterator lastGeneratedFormula, int transactionID)
457 throws RemoteException {
458 logger_.fatal(" . . <-BR: informListeners (unc="
459 + lastUnchangedFormula.toSMLString() + ", del="
460 + lastDeletedFormula.toSMLString() + ", gen="
461 + lastGeneratedFormula.toSMLString());
462 Iterator listn_it = listeners_.iterator();
465 CalcChangedEvent e = new CalcChangedEvent(transactionID, true, // completed
466 lastUnchangedFormula, lastDeletedFormula, lastGeneratedFormula);
467 while (listn_it.hasNext()) {
468 dg = (IToUser) listn_it.next();
473 MathEngine getMathEngine() {
481 // Special iterator hotSpot: marks the currently active formula of
483 void setHotSpot(ICalcIterator iterator) {
484 hot_spot_ = iterator;
487 //WN0411 reminiscence to Dinopolis, drop it !?
488 //WN0501 ... _NO_: ... = return-value of autoCalculate,etc. =
489 // = CalcChangedEvent.transaction_id_
490 private int generateTransactionID() {
491 return (int) (Math.random() * 0xFFFF);
497 * @see isac.util.interfaces.IToCalc#getElementsFromTo(isac.util.interfaces.ICalcIterator,
498 * isac.util.interfaces.ICalcIterator, java.lang.Integer, boolean)
500 public Vector getElementsFromTo(ICalcIterator iterator_from,
501 ICalcIterator iterator_to, Integer level,
502 boolean result_includes_tactics) throws RemoteException {
503 logger_.fatal(" DG->BR: getElementsFromTo("
504 + iterator_from.toSMLString() + ", "
505 + iterator_to.toSMLString() + level + ")");
507 return mathEngine_.getElementsFromTo(this.id_, iterator_from,
508 iterator_to, level, result_includes_tactics);
509 } catch (RemoteException e) {
516 * @see isac.util.interfaces.IToCalc#tryMatch(CalcHead, CalcHeadCompoundID)
517 * FIXXXME.WN050610 change to: tryMatch( CalcHeadCompoundID)
519 public void tryMatch(CalcHead calcHead, CalcHeadCompoundID problemID)
520 throws NotInSpecificationPhaseException {
521 CalcHead newCalcHead = null;
523 //WN040924 newCalcHead =
524 // bridgeRMI.tryMatch(calcHead.getCalcTreeID(), problemID);
525 bridgeRMI_.tryMatch(calcHead.getCalcTreeID(), problemID);
526 if (newCalcHead == null) {
527 throw new NotInSpecificationPhaseException();
529 calcHead.fillValuesfrom(newCalcHead);
530 } catch (RemoteException e) {
531 // TODO Auto-generated catch block
537 * Refine a given problem for this CalcTree
540 * @return CalcHead, if the operation was successful, else null
542 public void tryRefine(CalcHead calcHead, CalcHeadCompoundID problemID)
543 throws NotInSpecificationPhaseException {
544 CalcHead newCalcHead = null;
546 //WN040924 newCalcHead =
547 // bridgeRMI.tryRefine(calcHead.getCalcTreeID(), problemID);
548 bridgeRMI_.tryRefine(calcHead.getCalcTreeID(), problemID);
549 if (newCalcHead == null) {
550 throw new NotInSpecificationPhaseException();
552 calcHead.fillValuesfrom(newCalcHead);
553 } catch (RemoteException e) {
554 // TODO Auto-generated catch block