src/java/isac/bridge/CalcTree.java
author wneuper
Tue, 14 Jun 2005 17:22:50 +0200
changeset 2391 59a60ef2a2c8
parent 2265 724052025566
child 2448 f6065237ac78
permissions -rw-r--r--
java: minor changes preparing tryMatch
     1 /*
     2  * Created on Sep 11, 2003
     3  * @author rgradisc
     4  */
     5 package isac.bridge;
     6 
     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;
    20 
    21 import java.io.Serializable;
    22 import java.rmi.RemoteException;
    23 import java.util.Iterator;
    24 import java.util.Vector;
    25 
    26 import org.apache.log4j.Logger;
    27 
    28 /**
    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.
    36  * 
    37  * @author Richard Gradischnegg
    38  */
    39 
    40 public class CalcTree implements IToCalc, Serializable {
    41 
    42 	private int id_;
    43 
    44 	private Vector listeners_;
    45 
    46 	private MathEngine mathEngine_;
    47 
    48 	private ICalcIterator hot_spot_;//WN040924 ..delete: control hotSpot --> DG
    49 
    50 	private IBridgeRMI bridgeRMI_;//WN040924 added for completeCalcHead & Co.
    51 
    52 	static Logger logger_ = Logger.getLogger(CalcTree.class.getName());
    53 
    54 	/**
    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
    61 	 * authoring-tools
    62 	 * 
    63 	 * @param identification
    64 	 *            for the CalcTree as delivered by the SML-kernel
    65 	 */
    66 	CalcTree(MathEngine me, int id) {
    67 		this.id_ = id;
    68 		this.mathEngine_ = me;
    69 		this.bridgeRMI_ = me.getBridgeRMI();//WN040924
    70 		listeners_ = new Vector();
    71 	}
    72 
    73 	/**
    74 	 * Attach another dialog to the existing calculation tree.
    75 	 * 
    76 	 * @param dlg
    77 	 *            The new Dialog to be attached to this CalcTree
    78 	 */
    79 	public void attach(DialogGuide dg) {
    80 		listeners_.add(dg);
    81 	}
    82 
    83 	/**
    84 	 * Get a new iterator referencing the root element of the calculation tree.
    85 	 * <p>
    86 	 * The functionality for navigating the calculation is implemented in the
    87 	 * CalcIterator object.
    88 	 * 
    89 	 * @return new instance of CalcIterator
    90 	 */
    91 	public ICalcIterator iterator() {
    92 		return new CalcIterator(this);
    93 	}
    94 
    95 	/**
    96 	 * Makes the passed formula the active formula, i.e. the formula the next
    97 	 * tactic is applied to.
    98 	 * 
    99 	 * @param newActiveFormula
   100 	 */
   101 	public void moveActiveFormula(ICalcIterator cit) {
   102 		try {
   103 			Position p = mathEngine_.moveActiveFormula(id_, cit.getPosition());
   104 			//			if (p == null)//WN0412 message ?!
   105 			//				return false;
   106 			//			else
   107 			//				return true;
   108 		} catch (RemoteException e) {
   109 			// TODO Auto-generated catch block
   110 			e.printStackTrace();
   111 		}
   112 	}
   113 
   114 	/**
   115 	 * @see isac.util.interfaces.IToCalc#startSolving()
   116 	 */
   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);
   121 		else
   122 			new StartSolvingException (tac);
   123 	}
   124 
   125 	/**
   126 	 * @see isac.util.interfaces.IToCalc#modifyCalcHead(isac.util.formulae.CalcHead)
   127 	 */
   128 	public void modifyCalcHead(CalcHead calcHead) {
   129 		logger_.fatal("  DG->BR: modifyCalcHead(" + calcHead.toSMLString());
   130 		CalcHead newCalcHead = null;
   131 		try {
   132 			//WN040924 newCalcHead = bridgeRMI.modifyCalcHead(calcHead);
   133 			bridgeRMI_.modifyCalcHead(calcHead);
   134 			//WN040924 calcHead.fillValuesfrom(newCalcHead);
   135 		} catch (RemoteException e) {
   136 			e.printStackTrace();
   137 		}
   138 	}
   139 
   140 	/**
   141 	 * @see isac.util.interfaces.IToCalc#completeCalcHead(isac.util.formulae.CalcHead)
   142 	 */
   143 	public void completeCalcHead() {
   144 		logger_.fatal("  DG->BR: completeCalcHead()");
   145 		try {
   146 			//WN040924 newCalcHead = bridgeRMI.completeCalcHead(calcHead);
   147 			bridgeRMI_.completeCalcHead(this.id_);
   148 			//WN040924 calcHead.fillValuesfrom(newCalcHead);
   149 		} catch (RemoteException e) {
   150 			e.printStackTrace();
   151 		}
   152 	}
   153 
   154 	/**
   155 	 * @see isac.util.interfaces.IToCalc#completeCalcHead(isac.util.formulae.CalcHead,
   156 	 *      int)
   157 	 * @param calcHead
   158 	 *            eventually updated by the user
   159 	 * @param completeItem
   160 	 *            requested by the DialogGuide
   161 	 * 
   162 	 * WN040924 copied from MathEngine
   163 	 * WN050429 
   164 	 */
   165 	public void completeCalcHead(CalcHead calcHead, int completeItem) {
   166 		//		CalcHead newCalcHead;
   167 		//		try {
   168 		//			//WN040924 newCalcHead = bridgeRMI.completeCalcHead(calcHead,
   169 		//			// completeItem);
   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);
   174 		//
   175 		//		} catch (RemoteException e) {
   176 		//			e.printStackTrace();
   177 		//		}
   178 	}
   179 
   180 	/**
   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
   183 	 * 
   184 	 * @param scope
   185 	 *            The scope parameter can have following values:
   186 	 *            <ul>
   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.
   190 	 *            </ul>
   191 	 *            Constants for this scopes are found in the IToCalc class
   192 	 * @param nSteps
   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.
   197 	 * 
   198 	 * WN0504 see differences to this method completely done by RG !
   199 	 */
   200 	public int autoCalculate(int scope, int nSteps) {
   201 		logger_.fatal("  DG->BR: autoCalculate(" + scope + ", " + nSteps + ")");
   202 		CalcChanged cc;
   203 		int transactionID = -1;
   204 		try {
   205 			cc = mathEngine_.autoCalculate(this.id_, scope, nSteps);
   206 			if (!(cc == null)) {
   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()),
   212 						transactionID);
   213 			}
   214 		} catch (RemoteException e) {
   215 			e.printStackTrace();
   216 		}
   217 		return transactionID;
   218 	}
   219 
   220 	/**
   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.
   224 	 * <p>
   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.
   228 	 * 
   229 	 * @param newFormula
   230 	 * @return The method will return 0 on success or a nonzero value indicating
   231 	 *         the status otherwise.
   232 	 */
   233 	public int replaceFormula(CalcFormula f) throws RemoteException {
   234 		logger_.fatal("  DG->BR: replaceFormula(" + f.toSMLString() + ")");
   235 		CalcChanged cc;
   236 		int transactionID = -1;
   237 		try {
   238 			cc = mathEngine_.replaceFormula(this.id_, f);
   239 			if (!(cc == null)) {
   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()),
   245 						transactionID);
   246 			}
   247 		} catch (RemoteException e) {
   248 			e.printStackTrace();
   249 		}
   250 		return 0;
   251 	}
   252 
   253 	/**
   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.
   259 	 * 
   260 	 * @param newFormula
   261 	 * @return The method will return 0 on success or a nonzero value indicating
   262 	 *         the status otherwise.
   263 	 */
   264 	public int appendFormula(CalcFormula f) throws RemoteException {
   265 		logger_.fatal("  DG->BR: appendFormula(" + f.toSMLString() + ")");
   266 		CalcChanged cc;
   267 		int transactionID = -1;
   268 		try {
   269 			cc = mathEngine_.appendFormula(this.id_, f);
   270 			if (!(cc == null)) {
   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()),
   276 						transactionID);
   277 			}
   278 		} catch (RemoteException e) {
   279 			e.printStackTrace();
   280 		}
   281 		return 0;
   282 	}
   283 
   284 	/**
   285 	 * @see isac.util.interfaces.IToCalc#intermediateSteps()
   286 	 */
   287 	public int intermediateSteps(ICalcIterator ci) throws RemoteException {
   288 		logger_.fatal("  DG->BR: intermediateSteps(" + ci.toSMLString() + ")");
   289 		CalcChanged cc;
   290 		int transactionID = -1;
   291 		try {
   292 			cc = mathEngine_.intermediateSteps(this.id_, ci);
   293 			if (!(cc == null)) {
   294 				transactionID = generateTransactionID();
   295 				informListeners(new CalcIterator(this, cc.getLastUnchanged()),
   296 						new CalcIterator(this, cc.getLastDeleted()),
   297 						new CalcIterator(this, cc.getLastGenerated()),
   298 						transactionID);
   299 			}
   300 		} catch (RemoteException e) {
   301 			e.printStackTrace();
   302 		}
   303 		return 0;
   304 	}
   305 
   306 	/**
   307 	 * Set a tactic for usage by autocalculate.
   308 	 * 
   309 	 * @param tactic
   310 	 *            the Tactic to be used in the the next step
   311 	 * @return The return value indicates success, failure or probable success
   312 	 *         at a later time.
   313 	 */
   314 	public int setNextTactic(Tactic tactic) {
   315 		logger_.fatal("  DG->BR: setNextTactic(" + tactic.toSMLString() + ")");
   316 		int result = -1;
   317 		try {
   318 			result = mathEngine_.setNextTactic(this.id_, tactic);
   319 			if (result == 0) {
   320 				hot_spot_.moveDown(); // move to the new formula/calcHead
   321 				// FIXXXME
   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());
   328 			}
   329 		} catch (RemoteException e) {
   330 			// TODO Auto-generated catch block
   331 			e.printStackTrace();
   332 		}
   333 		return -1;
   334 	}
   335 
   336 	//	public int setNextTactic(Tactic tactic) {
   337 	//		logger_.fatal(" DG->BR: setNextTactic(" + tactic.toSMLString() + ")");
   338 	//		int result = -1;
   339 	//		ICalcIterator it;
   340 	//		try {
   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());
   353 	//			}
   354 	//		} catch (RemoteException e) {
   355 	//			// TODO Auto-generated catch block
   356 	//			e.printStackTrace();
   357 	//		}
   358 	//		return -1;
   359 	//	}
   360 
   361 	/**
   362 	 * Retrieve the tactic proposed by the SML-Kernel for the next step in the
   363 	 * calculation.
   364 	 * 
   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
   367 	 */
   368 	public Tactic fetchProposedTactic() {
   369 		logger_.fatal("  DG->BR: fetchProposedTactic()");
   370 		try {
   371 			Tactic tac = mathEngine_.fetchProposedTactic(this.id_);
   372 			logger_.fatal("  DG<-BR: fetchProposedTactic <- "
   373 					+ tac.toSMLString());
   374 			return tac;
   375 		} catch (RemoteException e) {
   376 			// TODO Auto-generated catch block
   377 			e.printStackTrace();
   378 		}
   379 		logger_.fatal("  DG<-BR: fetchProposedTactic <- NULL helpless");
   380 		return null;
   381 	}
   382 
   383 //	/**
   384 //	 * Get a list of tactics applicable to the active formula.
   385 //	 * 
   386 //	 * @param scope
   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
   390 //	 *            applied.
   391 //	 * @return Array with applyable tactics
   392 //	 */
   393 //	public Tactic[] fetchApplicableTactics(int scope) {
   394 //		logger_.fatal("  DG->BR: fetchApplicableTactics(" + scope + ")");
   395 //		Tactic[] result = null;
   396 //		//		try {
   397 //		//			result = mathEngine_.fetchAppliableTactics(this.id_, scope);
   398 //		//		} catch (RemoteException e) {
   399 //		//			// TODO Auto-generated catch block
   400 //		//			e.printStackTrace();
   401 //		//		}
   402 //		return result;
   403 //	}
   404 
   405 	/**
   406 	 * Add a Listener to this CalcTree. Listeners will be informed about any
   407 	 * changes in the CalcTree.
   408 	 * 
   409 	 * @param listener
   410 	 *            the new Listener, has to implement the interface IToUser
   411 	 * @return true, if the listener has been added successfully
   412 	 */
   413 	public boolean addDataChangeListener(IToUser listener) {
   414 		logger_.fatal("  DG->BR: addDataChangeListener(" + listener + ")");
   415 		if (listeners_.contains(listener)) {
   416 			return false;
   417 		} else {
   418 			listeners_.add(listener);
   419 		}
   420 		return true;
   421 	}
   422 
   423 	/**
   424 	 * Retrieve the active formula in a CalcTree. This is the formula form where
   425 	 * the calculation will continue.
   426 	 * 
   427 	 * @return Iterator that marks the currently active formula
   428 	 */
   429 	public ICalcIterator getActiveFormula() {
   430 		logger_.fatal("  DG<>BR: getActiveFormula <- "
   431 				+ hot_spot_.toSMLString());
   432 		return (ICalcIterator) hot_spot_.clone();
   433 	}
   434 
   435 	/**
   436 	 * Destruct this CalcTree: the sml-Representation of the CalcTree is
   437 	 * disposed, the id can be used for a new CalcTree
   438 	 * 
   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
   442 	 */
   443 	public boolean destruct() {
   444 		try {
   445 			return mathEngine_.destruct(this.id_);
   446 		} catch (RemoteException e) {
   447 			// TODO Auto-generated catch block
   448 			e.printStackTrace();
   449 		}
   450 		return false;
   451 	}
   452 
   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();
   463 		//DialogGuide dg;
   464 		IToUser dg;
   465 		CalcChangedEvent e = new CalcChangedEvent(transactionID, true, // completed
   466 				lastUnchangedFormula, lastDeletedFormula, lastGeneratedFormula);
   467 		while (listn_it.hasNext()) {
   468 			dg = (IToUser) listn_it.next();
   469 			dg.calcChanged(e);
   470 		}
   471 	}
   472 
   473 	MathEngine getMathEngine() {
   474 		return mathEngine_;
   475 	}
   476 
   477 	public int getId() {
   478 		return id_;
   479 	}
   480 
   481 	// Special iterator hotSpot: marks the currently active formula of
   482 	// the calcTree
   483 	void setHotSpot(ICalcIterator iterator) {
   484 		hot_spot_ = iterator;
   485 	}
   486 
   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);
   492 	}
   493 
   494 	/*
   495 	 * (non-Javadoc)
   496 	 * 
   497 	 * @see isac.util.interfaces.IToCalc#getElementsFromTo(isac.util.interfaces.ICalcIterator,
   498 	 *      isac.util.interfaces.ICalcIterator, java.lang.Integer, boolean)
   499 	 */
   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 + ")");
   506 		try {
   507 			return mathEngine_.getElementsFromTo(this.id_, iterator_from,
   508 					iterator_to, level, result_includes_tactics);
   509 		} catch (RemoteException e) {
   510 			e.printStackTrace();
   511 		}
   512 		return null;
   513 	}
   514 
   515 	/**
   516 	 * @see isac.util.interfaces.IToCalc#tryMatch(CalcHead, CalcHeadCompoundID)
   517 	 * FIXXXME.WN050610 change to:       tryMatch(          CalcHeadCompoundID)
   518 	 */
   519 	public void tryMatch(CalcHead calcHead, CalcHeadCompoundID problemID)
   520 			throws NotInSpecificationPhaseException {
   521 		CalcHead newCalcHead = null;
   522 		try {
   523 			//WN040924 newCalcHead =
   524 			// bridgeRMI.tryMatch(calcHead.getCalcTreeID(), problemID);
   525 			bridgeRMI_.tryMatch(calcHead.getCalcTreeID(), problemID);
   526 			if (newCalcHead == null) {
   527 				throw new NotInSpecificationPhaseException();
   528 			}
   529 			calcHead.fillValuesfrom(newCalcHead);
   530 		} catch (RemoteException e) {
   531 			// TODO Auto-generated catch block
   532 			e.printStackTrace();
   533 		}
   534 	}
   535 
   536 	/**
   537 	 * Refine a given problem for this CalcTree
   538 	 * 
   539 	 * @param problemID
   540 	 * @return CalcHead, if the operation was successful, else null
   541 	 */
   542 	public void tryRefine(CalcHead calcHead, CalcHeadCompoundID problemID)
   543 			throws NotInSpecificationPhaseException {
   544 		CalcHead newCalcHead = null;
   545 		try {
   546 			//WN040924 newCalcHead =
   547 			// bridgeRMI.tryRefine(calcHead.getCalcTreeID(), problemID);
   548 			bridgeRMI_.tryRefine(calcHead.getCalcTreeID(), problemID);
   549 			if (newCalcHead == null) {
   550 				throw new NotInSpecificationPhaseException();
   551 			}
   552 			calcHead.fillValuesfrom(newCalcHead);
   553 		} catch (RemoteException e) {
   554 			// TODO Auto-generated catch block
   555 			e.printStackTrace();
   556 		}
   557 	}
   558 	
   559 }