capture
[rrq/gorite.git] / com / intendico / gorite / Capability.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.Inquirable;
23 import com.intendico.data.Query;
24 import com.intendico.data.Rule;
25 import com.intendico.data.Store;
26 import com.intendico.gorite.addon.Reflector;
27 import java.util.Collection;
28 import java.util.Hashtable;
29 import java.util.Iterator;
30 import java.util.Vector;
31
32 /**
33  * A Capability is a container of {@link Goal} hierarchies, which are
34  * accessible by their names, and understood to represent alternative
35  * ways in which that named goal may be achieved. It provides lookup
36  * context for {@link BDIGoal} goals.
37  *
38  * <p> A Capability may also contain {@link Rule} objects, which are
39  * added by the {@link #addRule} method. The {@link Rule} objects are
40  * collated into the owning {@link Performer} {@link
41  * Performer#rule_set rule_set} to be applied as part of the goal
42  * execution.
43  */
44 public class Capability {
45
46     /**
47      * The goals of this capability, clustered by name.
48      */
49     private Hashtable/*<String,Vector<Goal>>*/ goals =
50         new Hashtable/*<String,Vector<Goal>>*/();
51
52     /**
53      * The table of inqueriable belief structures of this capability,
54      * primarily understood qua the {@link Inquirable} interface. This
55      * table is initially built at construction time by {@link
56      * #putInquirable(Inquirable)} calls, and by elevating
57      * inqueriables of sub capabilities that are added to this
58      * capability.  Eventually, there is also a {@link
59      * #shareInquirables} invocation, which accepts incoming
60      * inqueriables, and the distributes this {@link Inquirable}
61      * collection downwards to sub capabilities. In general, all
62      * capabilities form the same name-to-store mapping throughout a
63      * performer, except where name conflicts arise.
64      */
65     private Hashtable/*<String,Inquirable>*/ inquirables =
66         new Hashtable/*<String,Inquirable>*/();
67
68     /**
69      * The inner capabilities of this capability.
70      */
71     private Vector/*<Capability>*/ inner;
72
73     /**
74      * The {@link Rule} objects of this capability.
75      */
76     private Vector/*<Rule>*/ rules;
77
78     /**
79      * The performer that has this capability.
80      */
81     Performer performer;
82
83     /**
84      * This interface is implemented by the deferred text form
85      * entities (rules or reflectors).
86      */
87     public interface Deferred {
88         /**
89          * The method by which this entity installs itself.
90          */
91         public void install();
92     }
93
94     /**
95      * The collection of deferred entities. This is set to null by the
96      * first {@link #shareInquirables(Collection)} call.
97      */
98     private Vector/*<Deferred>*/ deferred = new Vector/*<Deferred>*/();
99
100     /**
101      * Utility method to install a Deferred object subsequent to the
102      * first invokation of {@link #shareInquirables(Collection)}
103      */
104     public void add(Deferred entity) {
105         if ( deferred == null ) {
106             entity.install();
107         } else {
108             deferred.add( entity );
109         }
110     }
111
112     /**
113      * Constructs a vector of all goals under the given name, by
114      * considering the local table and recursively from inner
115      * capabilities.
116      */
117     public Vector/*<Goal>*/ lookup(String name) {
118         Vector/*<Goal>*/ g = new Vector/*<Goal>*/();
119         if ( goals.get( name ) != null )
120             g.addAll( (Vector/*<Goal>*/) goals.get( name ) );
121         if ( inner != null ) {
122             for ( Iterator/*<Capability>*/ e =
123                       inner.iterator(); e.hasNext(); ) {
124                 g.addAll( ((Capability)e.next()).lookup( name ) );
125             }
126         }
127         return g;
128     }
129
130     /**
131      * Add a goal to this capability.
132      */
133     public void addGoal(Goal g) {
134         Vector/*<Goal>*/ v = (Vector/*<Goal>*/) goals.get( g.getGoalName() );
135         if ( v == null ) {
136             v = new Vector/*<Goal>*/();
137             goals.put( g.getGoalName(), v );
138         }
139         v.add( g );
140     }
141
142     /**
143      * Add a plan to this capability.
144      */
145     public void addPlan(Plan g) {
146         addGoal( g );
147     }
148
149     /**
150      * Add an inner capability. All {@link #inquirables} of the added
151      * capability are added to the {@link #inquirables} of this
152      * capability, unless their name starts with underscore, or an
153      * equally named {@link Inquirable} is already defined.
154      *
155      * <p> Note that a capability tree built by adding children before
156      * grand children yield a different, less complete elevation of
157      * inquirables than if the grand children are added to the
158      * children first.
159      *
160      * <p> When adding a capability late (i.e., after the first
161      * shareInquirables invocation, or more precisely when {@link
162      * #deferred} is null), then {@link #shareInquirables} is invoked;
163      * it's only invoked on the added capability unless an inquirable
164      * was gained, in which case {@link #shareInquirables} is invoked
165      * on this capability, for distributing the gained inquirables
166      * over the whole capability sub tree.
167      *
168      * @see #shareInquirables(Collection)
169      */
170     public void addCapability(Capability c) {
171         if ( inner == null )
172             inner = new Vector/*<Capability>*/();
173         if ( ! inner.contains( c ) )
174             inner.add( c );
175         if ( performer != null ) {
176             c.setPerformer( performer );
177         }
178         boolean extended = false;
179         for ( Iterator/*<Inquirable>*/ si = c.inquirables.values().iterator();
180               si.hasNext(); ) {
181             Inquirable inquirable = (Inquirable) si.next();
182             String name = inquirable.getName();
183             if ( ( ! name.startsWith( "_" ) ) &&
184                  inquirables.get( name ) == null ) {
185                 putInquirable( inquirable );
186                 extended = true;
187             }
188         }
189         if ( deferred == null ) {
190             if ( extended ) {
191                 shareInquirables( null );
192             } else {
193                 c.shareInquirables( inquirables.values() );
194             }
195         }
196     }
197
198     /**
199      * Creates a new {@link Rule} object with given antecedent and
200      * consequent {@link Query} objects.
201      */
202     public void addRule(Query a,Query c) {
203         if ( rules == null )
204             rules = new Vector/*<Rule>*/();
205         Rule r = new Rule( a, c );
206         rules.add( r );
207         if ( performer != null ) {
208             if ( Goal.isTracing() )
209                 System.err.println( "** Installing " + r + " for " + performer );
210             performer.rule_set.add( r );
211         }
212     }
213
214     /**
215      * Utility method to lookup a given goal name.
216      */
217     public boolean hasGoal(String name) {
218         if ( goals.get( name ) != null )
219             return true;
220         if ( inner == null )
221             return false;
222         for ( Iterator/*<Capability>*/ ci = inner.iterator(); ci.hasNext(); ) {
223             if ( ((Capability) ci.next()).hasGoal( name ) )
224                 return true;
225         }
226         return false;
227     }
228
229     /**
230      * Tells whether or not this capability provides some method or
231      * methods for all named goals.
232      */
233     public boolean hasGoals(String [] gs) {
234         if ( gs == null )
235             return true;
236         for ( int i = 0; i < gs.length; i++ ) {
237             if ( ! hasGoal( gs[i] ) )
238                 return false;
239         }
240         return true;
241     }
242
243     /**
244      * Returns an Inquirable qua Store, or null if it's not a Store.
245      */
246     public Store getStore(String name) {
247         Object x = inquirables.get( name );
248         if ( x instanceof Store )
249             return (Store) x;
250         return null;
251     }
252
253     /**
254      * Returns the Inquirable as mapped, or null if not found.
255      */
256     public Inquirable getInquirable(String name) {
257         return (Inquirable) inquirables.get( name );
258     }
259
260     /**
261      * Registers an {@link Inquirable} to be mapped. A Capability
262      * extension should register all locally created inquirables.
263      */
264     public void putInquirable(Inquirable inquirable) {
265         inquirables.put( inquirable.getName(), inquirable );
266     }
267
268     /**
269      * Registers an {@link Inquirable} under an alias. A Capability
270      * extension should register all locally created inquirables.
271      */
272     public void putInquirable(String name,Inquirable inquirable) {
273         inquirables.put( name, inquirable );
274     }
275
276     /**
277      * This method extends the inquirables collection with the given
278      * collection, then propagates its map downwards to sub
279      * capabilities. Finally all {@link Deferred} entities held in
280      * {@link #deferred} are installed, before setting {@link
281      * #deferred} to null.
282      *
283      * <p> Note that a {@link Performer} (which is a Capability) will
284      * invoke this once the first time it is added to the {@link
285      * Executor default executor}. A multi {@link Executor} model may
286      * need additional, explicit initial calls to this method in order
287      * to establish complete inquirables sharing.
288      *
289      * @see #addCapability(Capability)
290      */
291     public void shareInquirables(Collection/*<Inquirable>*/ shared) {
292         if ( Goal.isTracing() ) {
293             System.err.println( "** Sharing inquirables in " + this );
294         }
295         // Install incoming inquirables unless defined locally
296         if ( shared != null ) {
297             for ( Iterator/*<Inquirable>*/ si =
298                       shared.iterator(); si.hasNext(); ) {
299                 Inquirable inquirable = (Inquirable) si.next();
300                 if ( inquirables.get( inquirable.getName() ) == null ) {
301                     putInquirable( inquirable );
302                 }
303             }
304         }
305         // Propagate all local inquirables to inner capabilities
306         if ( inner != null ) {
307             shared = inquirables.values();
308             for ( Iterator/*<Capability>*/ i = inner.iterator();
309                   i.hasNext(); ) {
310                 Capability c = (Capability) i.next();
311                 c.shareInquirables( shared );
312             }
313         }
314         // Install deferred entities
315         if ( deferred != null ) {
316             for ( Iterator/*<Deferred>*/ di = deferred.iterator();
317                   di.hasNext(); ) {
318                 ((Deferred) di.next()).install();
319             }
320         }
321         deferred = null;
322     }
323
324     /**
325      * Sets the performer for this capability, and propagates it to
326      * all inner capabilities.
327      */
328     public void setPerformer(Performer p) {
329         if ( performer != null ) {
330             if ( performer != p ) {
331                 // The capability is moved
332                 throw new Error( "Invalid GORITE model" );
333             }
334             return;
335         }
336         performer = p;
337         if ( rules != null ) {
338             for ( Iterator/*<Rule>*/ i = rules.iterator(); i.hasNext(); ) {
339                 Rule r = (Rule) i.next();
340                 performer.rule_set.add( r );
341             }
342         }
343         if ( inner != null ) {
344             for ( Iterator/*<Capability>*/ i =
345                       inner.iterator(); i.hasNext(); ) {
346                 Capability c = (Capability) i.next();
347                 c.setPerformer( p );
348             }
349         }
350         initialize();
351     }
352
353     /**
354      * Overridable method where to add Capability initialisation
355      * code. This method is invoked when the performer is set up, and
356      * all inner capabilites are initialized. This base implementation
357      * does not do anything.
358      */
359     public void initialize() {
360     }
361
362     /**
363      * Returns the performer that has this capability.
364      */
365     public Performer getPerformer() {
366         return performer;
367     }
368
369     /**
370      * Utility method that creates the goal of establishing a
371      * task team.
372      */
373     public Goal deploy(String name) {
374         return new Goal( "deploy " + name ) {
375             public States execute(Data d) {
376                 String ttn = getGoalName().substring( 7 );
377                 Team t = (Team) performer;
378                 Team.TaskTeam tt = t.getTaskTeam( ttn );
379                 if ( tt == null )
380                     throw new Error( "Missing task team '" + ttn +
381                                      "' in team '" + t.getName() + "'" );
382                 if ( tt.establish( d ) )
383                     return States.PASSED;
384                 return States.FAILED;
385             }
386         };
387     }
388
389     /**
390      * Adds a {@link Reflector} to this capability. The actual
391      * addition is deferred until after the inquirables are shared, at
392      * which time the (@link Performer} is known.
393      */
394     public void addReflector(
395         final String goal,final String todo,final Query query) {
396         add( new Deferred() {
397             /**
398              * Installs this as a proper {@link Reflector}.
399              */
400             public void install() {
401                 Reflector r = new Reflector( getPerformer(), goal, todo );
402                 r.addQuery( query );
403             }
404         } );
405     }
406
407     /**
408      * Returns the {@link #inquirables} collection.
409      */
410     public Hashtable/*<String,Inquirable>*/ getInquirables() {
411         return inquirables;
412     }
413
414     /**
415      * Return the goals table.
416      */
417     public Hashtable/*<String,Vector<Goal>>*/ getGoals() {
418         return goals;
419     }
420
421     /**
422      * Return the inner capabilities, if any.
423      */
424     public Vector/*<Capability>*/ getInner() {
425         return inner;
426     }
427 }