View Javadoc

1   package cz.cuni.amis.pogamut.sposh.elements;
2   
3   import cz.cuni.amis.pogamut.sposh.exceptions.CycleException;
4   import cz.cuni.amis.pogamut.sposh.exceptions.DuplicateNameException;
5   import cz.cuni.amis.pogamut.sposh.exceptions.FubarException;
6   import cz.cuni.amis.pogamut.sposh.exceptions.InvalidNameException;
7   import cz.cuni.amis.pogamut.sposh.executor.IWorkExecutor;
8   import java.util.List;
9   import java.awt.datatransfer.DataFlavor;
10  import java.util.Collections;
11  import java.util.logging.Level;
12  import java.util.logging.Logger;
13  
14  /**
15   * Triggered action is basically a call of some other entity that is supposed to
16   * be executed. The other entity can be action (through {@link IWorkExecutor}, {@link Competence}
17   * or {@link ActionPattern}. The call needs name of a callee and possibly some
18   * arguments to pass.
19   * <p/>
20   * How is the target determined? Engine takes the name and checks if there is a {@link Competence}
21   * or {@link ActionPattern} with same name (names of all C and AP are unique,
22   * otherwise they get {@link DuplicateNameException}). If there is, the action
23   * will execute the found C/AP. If there is no such C/AP, it assumes that is is
24   * a name of an action so it tries to use {@link IWorkExecutor}. If that fails,
25   * stop the bot.
26   * <p/>
27   * Note that we do not allow cycles (thx to {@link CycleException}).
28   *
29   * @author HonzaH
30   */
31  public class TriggeredAction extends NamedLapElement {
32  
33      private PrimitiveCall actionCall;
34      public static final DataFlavor dataFlavor = new DataFlavor(TriggeredAction.class, "triggered_action");
35      public static final String taName = "taName";
36      public static final String taArgs = "taAruments";
37  
38      TriggeredAction(String actionName) {
39          this.actionCall = new PrimitiveCall(actionName);
40      }
41  
42      TriggeredAction(PrimitiveCall actionCall) {
43          this.actionCall = actionCall;
44      }
45  
46      @Override
47      public List<PoshElement> getChildDataNodes() {
48          return Collections.<PoshElement>emptyList();
49      }
50  
51      @Override
52      public String toString() {
53          return actionCall.toString();
54      }
55  
56      @Override
57      public String getName() {
58          return actionCall.getName();
59      }
60  
61      public PrimitiveCall getActionCall() {
62          return actionCall;
63      }
64  
65      /**
66       * Set name of the action.
67       *
68       * @param newName New name of an action
69       * @throws InvalidNameException If name is not valid
70       * @throws CycleException if namechange would cause a cycle.
71       */
72      public void setActionName(String newName) throws InvalidNameException, CycleException {
73          newName = newName.trim();
74  
75          if (!newName.matches(IDENT_PATTERN)) {
76              throw InvalidNameException.create(newName);
77          }
78  
79          String oldName = this.getName();
80          this.actionCall = new PrimitiveCall(newName, actionCall.getParameters());
81  
82          if (getRootNode() != null && getRootNode().isCycled()) {
83              this.actionCall = new PrimitiveCall(oldName, actionCall.getParameters());
84              throw CycleException.createFromName(newName);
85          }
86          firePropertyChange(taName, oldName, newName);
87      }
88  
89      @Override
90      public boolean moveChild(int newIndex, PoshElement child) {
91          throw new UnsupportedOperationException();
92      }
93  
94      @Override
95      public DataFlavor getDataFlavor() {
96          return dataFlavor;
97      }
98  
99      /**
100      * Take @source action and set all properties (name, parameters...) to be
101      * same as the @source. All changes will be emitted.
102      *
103      * @param source The source of the data this action will synchronize to.
104      */
105     public void synchronize(TriggeredAction source) throws CycleException {
106         try {
107             this.setActionName(source.getName());
108             // TODO: Implement parameters copy
109             assert source.getActionCall().getParameters().isEmpty();
110             assert actionCall.getParameters().isEmpty();
111         } catch (InvalidNameException ex) {
112             throw new FubarException("Name of the source action \"" + source.getName() + "\" is not valid for this action.", ex);
113         }
114     }
115 
116     /**
117      * Get parameters that can be used as arguments of teh action call. The
118      * parameters are specified in after the "vars" keyword in the parent.
119      *
120      * If this action is not part of 
121      * @return List of parameters or null if the action doesn't have parent.
122      */
123     private FormalParameters getParentParameters() {
124         PoshElement parent = getParent();
125         
126         if (parent == null) {
127             return null;
128         }
129         
130         if (parent instanceof DriveElement) {
131             return new FormalParameters();
132         }
133         if (parent instanceof CompetenceElement) {
134             CompetenceElement cel = (CompetenceElement) parent;
135             Competence competence = cel.getParent();
136             return competence.getParameters();
137         }
138         if (parent instanceof ActionPattern) {
139             ActionPattern ap = (ActionPattern) parent;
140             return ap.getParameters();
141         }
142         throw new IllegalStateException("Unexpected parent type " + parent.getClass().getCanonicalName());
143     }
144 
145     /**
146      * Action basically consists from
147      */
148     public void setArguments(Arguments newArguments) {
149         String actionName = actionCall.getName();
150         Arguments oldArguments = actionCall.getParameters();
151         this.actionCall = new PrimitiveCall(actionName, newArguments);
152 
153         // TODO: Check that all variables used as values in the newArguments are present in the parameters of parent, use getParentParameters().
154         
155         firePropertyChange(taArgs, oldArguments, newArguments);
156     }
157 
158     /**
159      * Get arguments of this action.
160      *
161      * @return Arguments of the action.
162      */
163     public Arguments getArguments() {
164         return this.actionCall.getParameters();
165     }
166 }