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 com.intendico.data.Query;
23 import com.intendico.data.Ref;
24 import com.intendico.data.Relation;
25 import java.util.Enumeration;
26 import java.util.HashSet;
27 import java.util.Hashtable;
28 import java.util.Iterator;
29 import java.util.Vector;
32 * The Team class is a base class for a structured task performer,
33 * i.e. a {@link Performer} that combine sub performers. A particular
34 * team type is defined by extending the Team class. The structure of
35 * an instance of a team type is defined by calls to the {@link
36 * #addPerformer} method. This provides a lookup context for inner
37 * {@link TaskTeam} objects, which are used to define particular sub
38 * team constallations for particular team tasks.
41 public class Team extends Performer {
44 * Default constructor.
50 * Constructor for team of given name.
52 public Team(String name)
58 * This is the current role filling for this team -- it's
59 * obligation structure.
61 public Vector/*<Performer>*/ performers = new Vector/*<Performer>*/();
64 * This is a table of TaskTeam objects, to support longer term
67 public Hashtable/*<String,TaskTeam>*/ groupings =
68 new Hashtable/*<String,TaskTeam>*/();
71 * Adds a particular performer in a named role filling.
73 synchronized public void addPerformer(Performer performer)
75 performers.add( performer );
76 for ( Iterator/*<TaskTeam>*/ ti = groupings.values().iterator();
78 ((TaskTeam) ti.next()).updateFillers( performer );
83 * Adds multiple, named performers.
85 public void addPerformers(Performer [] p)
89 for ( int i = 0; i < p.length; i++ )
95 * Utility method to pick a performer. Return null when the index
98 synchronized public Performer getPerformer(int i) {
99 if ( i < 0 || i >= performers.size() )
101 return (Performer) performers.get( i );
105 * Utility method to pick a performer by name. Returns the first
106 * Performer of this team with the given name, or null.
108 public Performer getPerformer(String name) {
109 for ( Iterator/*<Performer>*/ i =
110 performers.iterator(); i.hasNext(); ) {
111 Performer p = (Performer) i.next();
112 if ( name.equals( p.name ) ) {
120 * Utility method to remove a performer by name. Removes and
121 * returns the first Performer with the given name, or null;
123 public Performer removePerformer(String name) {
124 for ( Iterator/*<Performer>*/ i =
125 performers.iterator(); i.hasNext(); ) {
126 Performer p = (Performer) i.next();
127 if ( name.equals( p.getName() ) ) {
136 * Utility method to access a long term TaskTeam by name.
138 public TaskTeam getTaskTeam(String name) {
139 return (TaskTeam) groupings.get( name );
143 * Utility method to define a long term TaskTeam by unique name.
145 public void setTaskTeam(String name,TaskTeam group) {
146 groupings.put( name, group );
147 group.updateFillers( performers );
151 * A TaskTeam represents a sub-grouping of a team's performers
152 * into roles as appropriate for particular team activities. Each
153 * TaskTeam is populated to hold a selection of performers that
154 * are nominated for the task team roles according to their
155 * abilities. This role filling defines the candidates for acting
156 * in the roles when the TaskTeam is "established" in a particular
159 * <p> The role filling in a TaskTeam as well as the established
160 * role filling in an intention may be changed at any time. When
161 * the TaskTeam is installed for a {@link Team}, the current
162 * {@link #performers} collection is revide and performers are
163 * nominated to roles as appropriate. Thereafter each subsequently
164 * added {@link Performer} is automatically considered, and
165 * nominated to roles of installed TaskTeams as appropriate. The
166 * detail nomination decision is made by the overridable {@link
167 * Role#canFill(Performer)} method, which by default ensures
168 * distinct, singular role filling, and that the nominated
169 * {@link Performer} has plans for all required goals.
171 * <p> The TaskTeam is deployed on demand for intentions,
172 * typically by by means of {@link #deploy(String)} goal in team
173 * plans. When deployed in this way, the TaskTeam role filling is
174 * established in the intention {@link Data} via {@link
175 * #establish(Data)}, with a further filtering through the
176 * overridable {@link Role#canAct(Data,Performer)} method, which
177 * by default is "true".
179 public class TaskTeam {
182 * The roles of the task team.
184 public Vector/*<Role>*/ roles = new Vector/*<Role>*/();
187 * The population of this task team, held as a {@link
188 * Relation} beteen roles and performers.
190 public Relation fillers = new Relation( "fillers", 2 );
193 * Utility method to add a role to the task team.
195 public void addRole(Role r) {
201 * Utility method to remove a role from the task team. This
202 * also removes any population for the role.
204 public void removeRole(Role r) {
207 filling( r, new Ref( "$p" ) ).remove();
211 * Utility method to return a role filling {@link Query}
212 * object for a given role and performer, either of which is
213 * given as a constant of its type, null, or a {@link Ref}
214 * object, which may be (appropriately) bound or unbound.
216 public Query filling(Object r,Object p) {
218 return fillers.get( new Object [] { r, p } );
219 } catch (Exception e) {
226 * Utility method to define a role filler for a role.
228 public void fillRole(Role r,Performer p) {
229 filling( r, p ).add();
233 * Utility method to clear all filling.
235 public void clearFilling() {
236 filling( null, null ).remove();
240 * Updates the role nominations for the given {@link Performer
241 * performers}. This method simply iterates over the
242 * collection and updates each performer one by one via {@link
243 * #updateFillers(Performer)}.
245 public void updateFillers(Vector/*<Performer>*/ performers) {
246 for ( Iterator/*<Performer>*/ pi = performers.iterator();
248 updateFillers( (Performer) pi.next() );
253 * Updates the role nominations for the given {@link
254 * Performer} as appropriate for roles in this taks team.
255 * Which roles it is nominated to, if any, is determined by
256 * {@link Role#canFill(Performer)}.
258 public void updateFillers(Performer p) {
259 for ( Iterator/*<Role>*/ ri = roles.iterator(); ri.hasNext(); ) {
260 Role r = (Role) ri.next();
261 Query q = filling( r, p );
262 if ( r.canFill( p ) ) {
263 if ( Goal.isTracing() ) {
265 "** can Fill: " + r.name + " " + p );
269 if ( Goal.isTracing() ) {
271 "** cannot Fill: " + r.name + " " + p );
279 * Utility method to establish the role filling in the given
280 * intention data. This will establish the roles one by one in
281 * declaration order, using the current fillers as filtered by
282 * the {@link Role#canAct} method.
284 * <p> Note that role filling is set up as data elements using
285 * the role names. The value for a role name is the collection
286 * of fillers that can act in the role, qua {@link
287 * Capability}, but actually represented by {@link
288 * Performer.RoleFilling} objects as returned by the {@link
289 * Performer#fillRole(Team.Role)} method.
290 * @return true if all roles have some filling
292 public boolean establish(Data d) {
293 if ( Goal.isTracing() ) {
294 System.err.println( "** establish task team" );
296 for ( Iterator/*<Role>*/ ri = roles.iterator();
298 Role role = (Role) ri.next();
299 Ref $p = new Ref( "$p" );
300 Query q = filling( role, $p );
301 d.forget( role.name );
302 boolean filled = false;
303 HashSet actors = Team.getActors( role.name, d );
306 Performer candidate = (Performer) $p.get();
307 if ( actors.contains( candidate ) ) {
308 if ( Goal.isTracing() ) {
310 "** already Acting: " + role.name +
313 } else if ( role.canAct( d, candidate ) ) {
314 if ( Goal.isTracing() ) {
316 "** can Act: " + role.name +
319 Capability c = candidate.fillRole( role );
321 d.setValue( role.name, c );
323 } else if ( Goal.isTracing() ) {
325 "** refuses to Act: " + role.name +
328 } else if ( Goal.isTracing() ) {
330 "** cannot Act: " + role.name +
334 } catch (Exception e) {
338 if ( Goal.isTracing() ) {
340 "** Role not established: " + role.name );
342 return false; // couldn't establish the role at
350 * Utility method that creates a {@link Goal} of establishing
351 * this task team in the intention data when the goal is to be
353 * @see #establish(Data)
355 public Goal deploy(String name) {
356 return new Goal( "deploy " + name ) {
357 public States execute(Data d) {
358 return establish( d )? States.PASSED : States.FAILED;
364 * Utility method to collate all actors of this TaskTeam's
365 * roles in the given Data.
366 * @return a Hashtable of {@link Performer} HashSets, keyed by
367 * the {@link Role} names of the TaskTeam's roles.
369 public Hashtable/*<String,HashSet<Performer>>*/ getActors(Data d) {
370 Hashtable result = new Hashtable();
371 for ( Iterator/*<Role>*/ ri = roles.iterator(); ri.hasNext(); ) {
372 Role r = (Role) ri.next();
373 HashSet/*<Performer>*/ actors = Team.getActors( r.name, d );
374 if ( actors != null )
375 result.put( r.name, actors );
381 * Utility method to return the enclosing team wherein this
382 * TaskTeam object is created.
390 * Utility method to collate the performers defined to act in the
391 * given role in a given Data.
392 * @see TaskTeam#getActors(Data)
394 static public HashSet/*<Performer>*/ getActors(String r,Data d) {
395 HashSet/*<Performer>*/ result = new HashSet/*<Performer>*/();
396 Data.Element e = d.find( r );
398 for ( Iterator/*<Object>*/ vi = e.values.iterator();
400 result.add( ((Capability) vi.next()).getPerformer() );
407 * The Role class is a base class for representing team members in
408 * a team. Role extends {@link Capability}, so as to hold {@link
409 * Goal} methods that are tied to the role within the context of a
410 * {@link Team}. It further contains an attribute {@link
411 * #required}, which indicate goals that are required by a {@link
412 * Performer} of the role.
414 public class Role extends Capability {
417 * The reference name for this role.
422 * The goal names required by a role filler.
424 public String [] required;
427 * The {@link TaskTeam} that this role is a role of. This is
428 * set by the {@link TaskTeam#addRole} method when the role is
431 public TaskTeam group;
434 * Constructor that takes an array of required goals.
436 public Role(String n,String [] r) {
439 setPerformer( Team.this );
443 * Overrides {@link Capability#addCapability} so as to link up
444 * added capabilities with this team qua performer.
446 public void addCapability(Capability c) {
447 c.setPerformer( Team.this );
448 super.addCapability( c );
452 * Returns the team of the role.
459 * Overridable method that determines if the given performer
460 * can fill this role (within its {@link TaskTeam} {@link
461 * #group}). The default decision implemented by this
462 * method ensures that: <ol>
464 * <li> the performer is not already filling another role,
466 * <li> the role is not already filled by another performer,
469 * <li> the performer has some plans to achieve the required
474 public boolean canFill(Performer p) {
476 if ( group.filling( null, p ).next() )
478 if ( group.filling( this, null ).next() )
480 return p.hasGoals( required );
481 } catch (Exception e) {
488 * Overridable method that determines whether the given {@link
489 * Performer} can act in this role within the {@link
490 * Goal.Instance intention} represented by the given {@link
491 * Data}. The default decision is "yes".
492 * @see Team#getActors(String,Data)
494 public boolean canAct(Data d,Performer p) {