capture
[rrq/gorite.git] / com / intendico / gorite / TransferGoal.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.data.Query;
23
24 /**
25  * The TransferGoal class is utility class for wrapping a goal that is
26  * transferred into a different target performer context.
27  */
28 public class TransferGoal extends Plan {
29
30     /**
31      * Holds the target performer.
32      */
33     public Performer target;
34
35     /**
36      * Holds the transferred goal.
37      */
38     public Goal goal;
39
40     /**
41      * Constructor.
42      */
43     public TransferGoal(Performer to,Goal g) {
44         super( g.getGoalName() );
45         target = to;
46         goal = g;
47     }
48
49     /**
50      * Constructor without Performer, which instead is looked up
51      * at instantiation using the control string.
52      */
53     public TransferGoal(Goal g) {
54         super( g.getGoalName() );
55         target = null;
56         goal = g;
57     }
58
59     /**
60      * Overrides the base class method {@link Goal#instantiate} to
61      * provide a wrapper instance for the transferred goal.
62      */
63     public Instance instantiate(String h,Data d) {
64         return new TransferInstance( h, d );
65     }
66
67     /**
68      * Transfer goals are equals by the goals they transfer.
69      */
70     public boolean equals(Object x) {
71         return x instanceof TransferGoal && equals( (TransferGoal) x );
72     }
73
74     /**
75      * Transfer goals are equals by the goals they transfer.
76      */
77     public boolean equals(TransferGoal x) {
78         return goal.equals( x.goal );
79     }
80
81     /**
82      * Wrapper class for transfer goal instances.
83      */
84     public class TransferInstance extends Instance {
85
86         /**
87          * Holds the instance of the transferred goal.
88          */
89         public Instance instance;
90
91         public Performer into;
92         /**
93          * Constructor. Constructs an instance of the transferred
94          * goal while temporarily shifting into the target
95          * performer. 
96          */
97         public TransferInstance(String h,Data d) {
98             super( h );
99             instance = goal.instantiate( h + "|", d );
100         }
101
102         /**
103          * Control callback whereby the intention gets notified that
104          * it is cancelled. This will forward the cancellation to the
105          * currently progressing instance, if any.
106          */
107         public void cancel() {
108             if ( instance != null )
109                 instance.cancel();
110         }
111
112         /**
113          * Implements the instance action, which sets the target
114          * performer as {@link Goal#PERFORMER}, then invokes the
115          * target instance, and thereafter restores the performer.
116          */
117         public States action(String h,Data d)
118             throws LoopEndException, ParallelEndException {
119             Performer from = (Performer) d.getValue( PERFORMER );
120             try {
121                 if ( target == null ) {
122                     into = (Performer) d.getValue( getGoalControl() );
123                 } else {
124                     into = target;
125                 }
126                 // Note the use of setValue() rather than
127                 // replaceValue() below. This is done to ensure
128                 // that PERFORMER is set in the local data
129                 // context, without replacing PERFORMER in the
130                 // parent context.
131                 //
132                 // Also, the new PERFORMER is pushed on top of
133                 // any existing value, showing the chain of
134                 // performers involved in the computation.  Unless
135                 // the data context is in "goldfish" mode of
136                 // course.
137                 d.setValue( PERFORMER, into );
138                 if ( isTracing() )
139                     System.err.println( ">> " + into );
140                 return instance.perform( d );
141             } finally {
142                 // Note that restoreValue only affects the local
143                 // data context.
144                 d.restoreValue( PERFORMER, from );
145                 if ( isTracing() )
146                     System.err.println( "<< " + into );
147             }
148         }
149     }
150
151     /**
152      * Implements the {@link Context#context} method by forwarding to
153      * the wrapped goal.
154      */
155     public Query context(Data d) throws Exception {
156         if ( goal instanceof Context ) {
157             Capability from = (Capability) d.getValue( PERFORMER );
158             try {
159                 if ( isTracing() ) {
160                     System.err.println( "~(context)> (" + target + ")" );
161                 }
162                 d.setValue( PERFORMER, target );
163                 return ((Context) goal).context( d ) ;
164             } finally {
165                 if ( isTracing() ) {
166                     System.err.println( "<(context)~ (" + target + ")" );
167                 }
168                 d.restoreValue( PERFORMER, from );
169             }
170         } else {
171             return null ;
172         }
173     }
174
175     /**
176      * Implements the {@link Precedence#precedence} method by
177      * forwarding to the wrapped goal.
178      */
179     public int precedence(Data d) {
180         if ( goal instanceof Precedence ) {
181             Capability from = (Capability) d.getValue( PERFORMER );
182             try {
183                 if ( isTracing() ) {
184                     System.err.println( "~(precedence)> (" + target + ")" );
185                 }
186                 d.setValue( PERFORMER, target );
187                 return ((Precedence) goal).precedence( d );
188             } finally {
189                 if ( isTracing() ) {
190                     System.err.println( "<(precedence)~ (" + target + ")" );
191                 }
192                 d.replaceValue( PERFORMER, from );
193             }
194         } else {
195             return DEFAULT_PRECEDENCE ;
196         }
197     }
198 }