capture
[rrq/gorite.git] / com / intendico / gorite / PlanChoiceGoal.java
1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
3
4 This file is part of GORITE.
5
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.
10
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.
15
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 **********************************************************************/
19
20 package com.intendico.gorite;
21
22 import com.intendico.gorite.Goal.States;
23 import com.intendico.data.*;
24 import java.util.Vector;
25
26 /**
27  * This is a utility class used by BDIGoal execution, to inject a plan
28  * choice goal for choosing the plan instance to pursue. It is not
29  * intended for explicit use within goal hierarchies.
30  *
31  * <p> The {@link BDIGoal} uses the {@link
32  * Performer#getPlanChoice(String)} method to determine whether or not
33  * a goal is asoicated with a plan choice goal. If this is the case,
34  * then it will create a PlanChoiceGoal instance for handling the
35  * choice of which of the applicable plan options to pursue next, and
36  * the subsequent execution of that option.
37  *
38  * <p> The choice is performed by triggering a (freschly created)
39  * {@link BDIGoal} for the plan choice goal, with a separate Data
40  * object that is initialised with "options", "failed" and "data". As
41  * the plan choice goal succeeds, the resulting "choice" data is used
42  * as being the choice of plan option, and then that plan option is
43  * executed as an attempt of achieving the original goal. If that
44  * succeeds, the original goal succeeds without further ado, and if it
45  * fails, then the BDIGoal forms a new, possibly empty collection of
46  * applicable (non-failed) plan options, and trigger a new
47  * PlanChoiceGoal for that collection.
48  *
49  * <p> If the plan choice goal fails, then all applicable options at
50  * this point are added to the failed set, the {@link BDIGoal}
51  * continues by forming a new, possibly empty collection of applicable
52  * (non-failed) plan options, and triggering a new PlanChoiceGoal for
53  * that collection.
54  *
55  * <p> If the plan choice goal fails for the final triggering, i.e,
56  * with an empty collection of applicable (non-failed) plan options,
57  * then the original goal fails. In fact, the orginal goal fails also
58  * if the final plan choice goal succeeds, except if this is also the
59  * first triggering and thus, there are no failed plan options
60  * either. In that case, the original goal will succeed if the plan
61  * choice goal succeeds.
62  *
63  * @see Performer#getPlanChoice(String)
64  * @see Performer#setPlanChoice(String,Object)
65  */
66 public class PlanChoiceGoal extends Goal {
67
68     /**
69      * The invocation data.
70      */
71     public Data choice_data;
72
73     /**
74      * Status flag for plan choice processing.
75      */
76     public States done = States.STOPPED;
77
78     /**
79      * The initial first option.
80      */
81     public Goal first;
82
83     /**
84      * The choice goal. This is set by the plan choice processing.
85      */
86     public Goal choice;
87
88     /**
89      * The currently executing goal instance.
90      */
91     public Instance instance = null;
92
93     /**
94      * Sub goal head, which is set when this goal is instantiated
95      */
96     public String head;
97
98     /**
99      * Constructor for a given plan choice goal and collection of plan
100      * instances.
101      */
102     public PlanChoiceGoal(
103         Performer p,String pg,Vector/*<Goal>*/ plans,Vector/*<Goal>*/ failed) {
104         super( pg );
105         choice_data = new Data();
106         choice_data.setValue( Goal.PERFORMER, p );
107         choice_data.setValue( "options", plans );
108         choice_data.setValue( "failed", failed );
109         if ( plans.size() > 0 )
110             first = (Goal) plans.get( 0 );
111     }
112
113     /**
114      * Instantiating this goal for execution.
115      */
116     public Goal.Instance instantiate(String h,Data d) {
117         head = h;
118         choice_data.setValue( "data", d );
119         instance = new BDIGoal(
120             getGoalName() ).instantiate( h + "?", choice_data );
121         return super.instantiate( h, d );
122     }
123
124     /**
125      * Control callback whereby the goal gets notified that an (its)
126      * intention is cancelled. This will forward the cancellation to
127      * the currently progressing instance, if any.
128      */
129     public void cancelled(Instance which) {
130         if ( instance != null )
131             instance.cancel();
132     }
133
134     /**
135      * Excution of this goal. If choice is null, then the execution is
136      * like a BDIGoal of the plan choice goal, with its data holding
137      * the "options", for setting the "choice". If that execution is
138      * successful, then the choice is taken, otherwise the original
139      * first choice is taken. If choice is set, then the execution
140      * executes that goal.
141      */
142     public States execute(Data data)
143         throws ParallelEndException {
144         for ( ;; ) {
145             States s = States.FAILED;
146             try {
147                 s = instance.perform( choice == null? choice_data: data );
148             } catch (LoopEndException e) {
149                 s = States.FAILED;
150             } catch (ParallelEndException e) {
151                 s = States.FAILED;
152                 if ( done != States.STOPPED )
153                     throw e;
154             }
155             if ( done != States.STOPPED )
156                 return s;
157             if ( s != States.PASSED && s != States.FAILED )
158                 return s;
159             done = s;
160             if ( s == States.FAILED ) {
161                 Vector/*<Goal>*/ options = (Vector/*<Goal>*/)
162                     choice_data.getValue( "options" );
163                 Vector/*<Goal>*/ failed = (Vector/*<Goal>*/)
164                     choice_data.getValue( "failed" );
165                 failed.addAll( options );
166                 choice = first;
167                 return States.FAILED;
168             }
169             choice = (Goal) instance.getValue( "choice" );
170             if ( choice == null )
171                 choice = first;
172             if ( choice == null ) {
173                 Vector/*<Goal>*/ failed = (Vector/*<Goal>*/)
174                     choice_data.getValue( "failed" );
175                 return failed.size() == 0? States.PASSED : States.FAILED;
176             }
177             instance = choice.instantiate( head + "!", data );
178         }
179     }
180
181 }