View Javadoc

1   package cz.cuni.amis.pogamut.sposh.elements;
2   
3   import cz.cuni.amis.pogamut.sposh.elements.LapPath.Link;
4   import cz.cuni.amis.pogamut.sposh.engine.VariableContext;
5   import java.beans.PropertyChangeEvent;
6   import java.util.HashSet;
7   import java.util.Iterator;
8   import java.util.LinkedList;
9   import java.util.List;
10  import java.util.Set;
11  
12  interface IChainLink {
13  
14      LapType getType();
15  
16      Arguments getArgs();
17  
18      FormalParameters getParams();
19  
20      PoshElement getReference();
21  
22      PoshElement getReferencedNode();
23  
24      void register(LapChain chain);
25  
26      void unregister(LapChain chain);
27  }
28  
29  /**
30   * Chain link representing call of primitive (action or sense).
31   */
32  class ReferenceChainLink<REFERENCE_ELEMENT extends PoshElement & IReferenceElement> extends ChainLink {
33  
34      private final REFERENCE_ELEMENT reference;
35      private final FormalParameters EMPTY_PARAMETERS = new FormalParameters();
36  
37      public ReferenceChainLink(REFERENCE_ELEMENT reference) {
38          this.reference = reference;
39      }
40  
41      @Override
42      public void register(LapChain chain) {
43          reference.addElementListener(chain);
44      }
45  
46      @Override
47      public void unregister(LapChain chain) {
48          reference.removeElementListener(chain);
49      }
50  
51      @Override
52      public LapType getType() {
53          return reference.getType();
54      }
55  
56      @Override
57      public FormalParameters getParams() {
58          return EMPTY_PARAMETERS;
59      }
60  
61      @Override
62      public Arguments getArgs() {
63          return reference.getArguments();
64      }
65  
66      @Override
67      public REFERENCE_ELEMENT getReference() {
68          return reference;
69      }
70  
71      @Override
72      public PoshElement getReferencedNode() {
73          return null;
74      }
75  
76      @Override
77      public boolean equals(Object obj) {
78          if (obj == null) {
79              return false;
80          }
81          if (getClass() != obj.getClass()) {
82              return false;
83          }
84          final ReferenceChainLink<REFERENCE_ELEMENT> other = (ReferenceChainLink<REFERENCE_ELEMENT>) obj;
85          if (this.reference != other.reference) {
86              return false;
87          }
88          return true;
89      }
90  
91      @Override
92      public int hashCode() {
93          int hash = 7;
94          return hash;
95      }
96  }
97  
98  /**
99   * Link representing referencing of {@link ReferencedNode} from some {@link TriggeredAction}.
100  */
101 class ReferenceNodeChainLink<REFERENCED_NODE extends PoshElement & IParametrizedElement> extends ChainLink {
102 
103     private final TriggeredAction action;
104     private final REFERENCED_NODE referencedNode;
105 
106     public ReferenceNodeChainLink(REFERENCED_NODE referencedNode, TriggeredAction action) {
107         this.referencedNode = referencedNode;
108         this.action = action;
109     }
110 
111     @Override
112     public LapType getType() {
113         return referencedNode.getType();
114     }
115 
116     @Override
117     public final Arguments getArgs() {
118         return action.getArguments();
119     }
120 
121     @Override
122     public final FormalParameters getParams() {
123         return referencedNode.getParameters();
124     }
125 
126     @Override
127     public final TriggeredAction getReference() {
128         return action;
129     }
130 
131     @Override
132     public REFERENCED_NODE getReferencedNode() {
133         return referencedNode;
134     }
135 
136     @Override
137     public void register(LapChain chain) {
138         referencedNode.addElementListener(chain);
139         action.addElementListener(chain);
140     }
141 
142     @Override
143     public void unregister(LapChain chain) {
144         action.removeElementListener(chain);
145         referencedNode.removeElementListener(chain);
146     }
147 
148     @Override
149     public boolean equals(Object obj) {
150         if (obj == null) {
151             return false;
152         }
153         if (getClass() != obj.getClass()) {
154             return false;
155         }
156         final ReferenceNodeChainLink<REFERENCED_NODE> other = (ReferenceNodeChainLink<REFERENCED_NODE>) obj;
157         if (this.action != other.action) {
158             return false;
159         }
160         if (this.referencedNode != other.referencedNode) {
161             return false;
162         }
163         return true;
164     }
165 
166     @Override
167     public int hashCode() {
168         int hash = 7;
169         return hash;
170     }
171 }
172 
173 /**
174  * One link of {@link ParametersChain} chain. Each link is basically a reference
175  * from {@link TriggeredAction action} to C/Ap/primitive, therefore we need
176  * arguments of the reference and parameters of the refereced.
177  */
178 abstract class ChainLink implements IChainLink {
179 
180     @Override
181     public String toString() {
182         return "{" + "params=" + getParams() + ", args=" + getArgs() + '}';
183     }
184 }
185 
186 /**
187  * Chain of links that represents how are parameters passed in the chain of lap
188  * elements. Each time action is referenced, it adds new chain of link.
189  *
190  * The chain itself is immutable. You can listen for changes of {@link FormalParameters parameters}
191  * and {@link Arguments} of {@link PoshElement elements} referenced by the
192  * individual links.
193  *
194  * Example1: There is only drive that calls some action. In such case, there is
195  * only one link of the chain - the call from the chain to the action.
196  *
197  * Example2: There is drive action that references AP1 and that AP1 references
198  * some action. In such case chain has two links - first link represents
199  * reference from drive action to AP1 and second link represents reference from
200  * AP1 to the action..
201  */
202 public final class LapChain implements PoshElementListener {
203 
204     /**
205      * All links of the chain. The last index is the last link of the chain.
206      */
207     private List<IChainLink> links;
208     /**
209      * Listeners for this chain.
210      */
211     private final Set<ILapChainListener> listeners = new HashSet<ILapChainListener>();
212 
213     /**
214      * Create new chain, It has no {@link ChainLink}.
215      */
216     public LapChain() {
217         links = new LinkedList<IChainLink>();
218     }
219 
220     /**
221      * Create chain from the @path.
222      *
223      * @param path Path that will be used as source of info.
224      * @return New chain.
225      */
226     public static LapChain fromPath(PoshPlan plan, LapPath path) {
227         LapChain chain = new LapChain();
228         Iterator<Link> iterator = path.iterator();
229         while (iterator.hasNext()) {
230             Link nodeLink = iterator.next();
231             int index = path.getLinkIndex(nodeLink) + 1;
232             LapPath nodePath = path.subpath(0, index);
233             PoshElement node = nodePath.traversePath(plan);
234             if (node instanceof TriggeredAction) {
235                 TriggeredAction reference = (TriggeredAction) node;
236                 chain = processReference(plan, path, chain, iterator, reference);
237             } else if (node instanceof Sense) {
238                 chain = chain.derive((Sense) node);
239             } else {
240                 // Ignore other nodes
241             }
242         }
243         return chain;
244     }
245 
246     private static LapChain processReference(PoshPlan plan, LapPath path, LapChain chain, Iterator<Link> iterator, TriggeredAction reference) {
247         if (iterator.hasNext()) {
248             Link referencedNodeLink = iterator.next();
249             LapPath processedPath = path.subpath(0, path.getLinkIndex(referencedNodeLink) + 1);
250             PoshElement referencedNode = processedPath.traversePath(plan);
251             if (referencedNode instanceof Competence) {
252                 chain = chain.derive(reference, (Competence) referencedNode);
253             } else if (referencedNode instanceof ActionPattern) {
254                 chain = chain.derive(reference, (ActionPattern) referencedNode);
255             } else if (referencedNode instanceof Adopt) {
256                 chain = chain.derive(reference, (Adopt) referencedNode);
257             } else {
258                 throw new IllegalStateException("Node " + referencedNodeLink + " is not a referenced node.");
259             }
260         } else {
261             chain = chain.derive(reference);
262         }
263         return chain;
264     }
265 
266     /**
267      * Create {@link LapPath} from the chain. Since not every {@link LapPath}
268      * can be represented by the chain (e.g. {@link LapType#COMPETENCE_ELEMENT}),
269      * it is not 1-on-1 mapping. Resulting {@link LapPath} always starts with
270      * /P:0 and ends with type of referenced node of last link. If there is not
271      * referenced node at last link (e.g. {@link Sense} or {@link TriggeredAction}),
272      * the last link of path is {@link LapType} of {@link IChainLink#getReference()
273      * }.
274      *
275      * If chain is empty, return {@link LapPath#DRIVE_COLLECTION_PATH}.
276      *
277      * @return Created path.
278      */
279     public LapPath toPath() {
280         if (links.isEmpty()) {
281             return LapPath.DRIVE_COLLECTION_PATH;
282         }
283         LapPath path = LapPath.PLAN_PATH;
284         Iterator<IChainLink> it = links.iterator();
285         IChainLink link;
286         do {
287             link = it.next();
288             LapPath linkPath = LapPath.getLinkPath(link.getReference());
289             path = path.concat(linkPath);
290         } while (it.hasNext());
291 
292         PoshElement referencedNode = link.getReferencedNode();
293         if (referencedNode != null) {
294             path = path.concat(referencedNode.getType(), referencedNode.getId());
295         }
296         return path;
297     }
298 
299     /**
300      * Create new chain by copying the original chain and appending one link at
301      * the end.
302      *
303      * @param chain Chain that will be copied.
304      * @param link last link of new chain.
305      */
306     private LapChain(LapChain chain, IChainLink link) {
307         this.links = new LinkedList<IChainLink>(chain.links);
308         this.links.add(link);
309     }
310 
311     /**
312      * Add the chain as listener for changes of elements of links. Chain can't
313      * notify its {@link ILapChainListener} unless it is registered.
314      */
315     public void register() {
316         for (IChainLink link : links) {
317             link.register(this);
318         }
319     }
320 
321     /**
322      * Remove the chain as listener of all links elements.
323      */
324     public void unregister() {
325         for (IChainLink link : links) {
326             link.unregister(this);
327         }
328     }
329 
330     /**
331      * Return new chain using this one as the base and create new link from the
332      * reference of action to AP.
333      *
334      * @param action action referencing the AP. Basis of the link.
335      * @param actionPattern referenced AP.
336      * @return Newly created chain.
337      */
338     public <REFERENCED_NODE extends PoshElement & IParametrizedElement> LapChain derive(TriggeredAction action, REFERENCED_NODE referencedNode) {
339         assert action.getName().equals(referencedNode.getName());
340 
341         return new LapChain(this, new ReferenceNodeChainLink(referencedNode, action));
342     }
343 
344     /**
345      * Create and return new chain using this one as the base. The last link is
346      * a leaf, either action or sense. Since we are calling primitive action,
347      * there is no referenced node.
348      *
349      * @param reference Reference to action or sense in work executor
350      * @return Newly created chain.
351      */
352     public <REFERENCE extends PoshElement & IReferenceElement> LapChain derive(REFERENCE reference) {
353         return new LapChain(this, new ReferenceChainLink(reference));
354     }
355 
356     /**
357      * Create subchain created from links of this chain.
358      * @param beginIndex Begin index of subchain, inclusive
359      * @param endIndex End index of subchain, exclusive
360      * @return 
361      */
362     public LapChain subchain(int beginIndex, int endIndex) {
363         LapChain subchain = new LapChain();
364         for (IChainLink link : links.subList(beginIndex, endIndex)) {
365             subchain = new LapChain(subchain, link);
366         }
367         return subchain;
368     }
369     
370     /**
371      * How many links of chain are there.
372      */
373     public int size() {
374         return links.size();
375     }
376 
377     @Override
378     public String toString() {
379         StringBuilder sb = new StringBuilder("Chain{");
380         boolean first = true;
381         for (IChainLink link : links) {
382             if (!first) {
383                 sb.append(',');
384             }
385             sb.append(link.toString());
386         }
387         sb.append('}');
388 
389         return sb.toString();
390     }
391 
392     /**
393      * @return Newly created {@link VariableContext} for current chain.
394      */
395     public VariableContext createContext() {
396         VariableContext ctx = new VariableContext();
397 
398         for (IChainLink link : links) {
399             ctx = new VariableContext(ctx, link.getArgs(), link.getParams());
400         }
401         return ctx;
402     }
403 
404     @Override
405     public void childElementAdded(PoshElement parent, PoshElement child) {
406     }
407 
408     @Override
409     public void childElementMoved(PoshElement parent, PoshElement child, int oldIndex, int newIndex) {
410     }
411 
412     @Override
413     public void childElementRemoved(PoshElement parent, PoshElement child, int removedChildPosition) {
414     }
415 
416     @Override
417     public void propertyChange(PropertyChangeEvent evt) {
418         emitLinkChanged();
419     }
420 
421     public boolean addChainListener(ILapChainListener listener) {
422         return listeners.add(listener);
423     }
424 
425     public boolean removeChainListener(ILapChainListener listener) {
426         return listeners.remove(listener);
427     }
428 
429     private void emitLinkChanged() {
430         ILapChainListener[] listenersArray = listeners.toArray(new ILapChainListener[listeners.size()]);
431 
432         for (ILapChainListener listener : listenersArray) {
433             listener.notifyLinkChanged();
434         }
435     }
436 
437     @Override
438     public boolean equals(Object obj) {
439         if (obj == null) {
440             return false;
441         }
442         if (getClass() != obj.getClass()) {
443             return false;
444         }
445         final LapChain other = (LapChain) obj;
446         if (this.links != other.links && (this.links == null || !this.links.equals(other.links))) {
447             return false;
448         }
449         return true;
450     }
451 
452     @Override
453     public int hashCode() {
454         int hash = 3;
455         hash = 31 * hash + (this.links != null ? this.links.hashCode() : 0);
456         return hash;
457     }
458 }