1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
4 This file is part of GORITE.
6 GORITE is free software: you can redistribute it and/or modify it
7 under the terms of the Lesser GNU General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GORITE is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the Lesser GNU General Public
17 License along with GORITE. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
20 package com.intendico.gorite;
22 import java.util.Vector;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.Observable;
26 import java.util.Observer;
29 * The BranchingGoal class is an intermediate, abstract class that
30 * provides common execution support for parallel branches.
32 abstract public class BranchingGoal extends Goal {
37 public BranchingGoal(String n,Goal [] sg) {
42 * Convenience constructor without sub goals.
44 public BranchingGoal(String n) {
49 * Helper class that implements suport for parallel goal execution
50 * with interrupt control.
52 abstract public class MultiInstance extends Instance {
55 * States of execution; the number of branches remaining.
60 * Currently active branches.
62 public Vector/*<Branch>*/ branches = null;
65 * Names of data elements that are output from any branch.
67 public HashSet/*<String>*/ outs = new HashSet/*<String>*/();
70 * Utility method for counting branches when they are created.
72 public synchronized void increment() {
79 public MultiInstance(String h) {
84 * A class to monitor the combined runnability of all the
85 * branches, by the logic that this intention is runnable if
86 * any of the branch intentions are runnable.
88 class RunnableMonitor extends Observable implements Observer {
90 private boolean some_runnable = false;
92 public void update(Observable x,Object y) {
93 if ( ! some_runnable ) {
99 x.deleteObserver( this );
105 * Keeps the monitor for branch runnability state.
107 private RunnableMonitor runnable_monitor = null;
110 * Utility class to set up runnability monitoring.
112 private void setupMonitor(Data d) {
113 runnable_monitor = new RunnableMonitor();
114 d.setTrigger( runnable_monitor );
115 boolean some = false;
116 for ( Iterator/*<Branch>*/ i =
117 branches.iterator(); i.hasNext(); ) {
118 some |= ((Branch)i.next()).setupObserver( d );
127 * Utility method to remove the runnability monitoring.
129 private void removeMonitor(Data d) {
130 runnable_monitor = null;
131 for ( Iterator/*<Branch>*/ i =
132 branches.iterator(); i.hasNext(); ) {
133 ((Branch)i.next()).removeObserver( d );
138 * Branch head and execution.
140 public class Branch {
143 * Collecting all outputs.
145 public HashSet/*<String>*/ outputs;
148 * The goal instance to execute.
150 public Instance instance;
153 * Branch thread name. This needs to be distinct from the
154 * actual branch Instance in order to join data properly.
156 public String thread_name;
159 * The Data operated on.
164 * Propagate cancellation to actual branch.
166 public void cancel() {
167 if ( instance != null ) {
173 * Constructor, tying the branch to a goal instance.
175 public Branch(int ix,Instance i,Data d,HashSet/*<String>*/ outs) {
180 thread_name = instance.thread_name + "(branch)";
181 data.fork( getGoalControl(), ix, thread_name );
185 * Branch main method: performs the associated goal
186 * instance, and manages current "thread name".
188 public States action()
189 throws LoopEndException, ParallelEndException {
190 String old = data.setThreadName( thread_name );
192 States s = instance.perform( data );
193 // TODO: collate all result data for join at end
194 if ( s == States.PASSED ) {
195 //data.join( getGoalControl(), outputs, thread_name );
196 data.join( getGoalControl(), null, thread_name );
197 } else if ( s == States.FAILED ) {
198 data.join( getGoalControl(), null, thread_name );
201 } catch (ParallelEndException e) {
202 //data.join( getGoalControl(), outputs, thread_name );
203 data.join( getGoalControl(), null, thread_name );
206 data.setThreadName( old );
211 * Utility method to set up the runnable_monitor as
212 * observer of runnability change for this branch, and
213 * then return the current runnability state.
215 boolean setupObserver(Data d) {
216 d.addObserver( instance.thread_name, runnable_monitor );
217 return d.isRunning( instance.thread_name );
221 * Utility method to remove the runnable_monitor as
222 * runnability observer.
224 void removeObserver(Data d) {
225 d.deleteObserver( instance.thread_name, runnable_monitor );
230 * Cancels the MultiInstance (Parallel or Repeat)
232 public void cancel() {
234 propagateCancel( null );
238 * Propagates cancel to all branches
240 public void propagateCancel(Branch skip)
242 if ( branches == null )
244 for ( Iterator/*<Branch>*/ i =
245 branches.iterator(); i.hasNext(); ) {
246 Branch b = (Branch) i.next();
253 * Process all subgoals in parallel, and complete when they
256 public States action(String head,Data d)
257 throws LoopEndException, ParallelEndException {
258 if ( branches == null ) {
259 branches = new Vector/*<Branch>*/();
260 for ( int i = 0; more( i, d ); i++ ) {
261 Instance instance = getBranch( i, head + ":" + i, d );
262 Branch b = new Branch( i, instance, d, outs );
267 if ( runnable_monitor != null ) {
275 while ( branches.size() > 0 ) {
276 States s = ((Branch)branches.get( 0 )).action();
277 if ( s == States.STOPPED || s == States.BLOCKED ) {
278 branches.add( branches.remove( 0 ) );
280 if ( s == States.BLOCKED )
282 if ( icount < branches.size() )
284 if ( bcount != icount )
285 return States.STOPPED;
287 return States.BLOCKED;
290 if ( s == States.PASSED ) {
291 branches.remove( 0 );
294 propagateCancel( (Branch)branches.get( 0 ) );
297 } catch (LoopEndException e) {
298 propagateCancel( null );
300 } catch (ParallelEndException e) {
301 propagateCancel( (Branch) branches.get( 0 ) );
302 // Discard data from cancelled branches
304 // Signal elevated branch outputs in calling data context.
305 for ( Iterator/*<String>*/ i =
306 outs.iterator(); i.hasNext(); ) {
307 String key = (String) i.next();
311 // TODO join collated data
312 return States.PASSED;
316 * The method for determining whether there is another branch.
318 abstract public boolean more(int i,Data d);
321 * Utility method to obtain the actual branch instance.
323 abstract public Instance getBranch(int i,String head,Data d);