View Javadoc

1   package cz.cuni.amis.pogamut.sposh.elements;
2   
3   import cz.cuni.amis.pogamut.sposh.engine.PoshEngine;
4   import cz.cuni.amis.pogamut.sposh.exceptions.CycleException;
5   import cz.cuni.amis.pogamut.sposh.exceptions.DuplicateNameException;
6   import cz.cuni.amis.pogamut.sposh.exceptions.InvalidNameException;
7   import java.awt.datatransfer.DataFlavor;
8   import java.util.ArrayList;
9   import java.util.List;
10  
11  /**
12   * Drive is a child of {@link DriveCollection}. What is drive? Basically it is a
13   * top node of decision tree. It has a trigger and an action. When trigger is
14   * satisfied, the drive is elegible to be traversed. Action is just a name, it
15   * can be reference (=having same name) to some action, but it can also be
16   * reference to C or AP.
17   * <p/>
18   * In posh it has following syntax(minus variables):
19   * <code>
20   *   (&lt;name&gt; [&lt;trigger&gt;] &lt;name&gt;)
21   * </code> The first name is name of the element and second name is name of the
22   * action.
23   * <p/>
24   * In the past, it used to have this form, but not anymore (none knew how to use
25   * it and no need to waste scarce resources to support unused features.)
26   * <code>
27   *   (&lt;name&gt; [&lt;trigger&gt;] &lt;name&gt; [&lt;freq&gt;] [&lt;comment&gt;])
28   * </code> The drive is elegible for execution if it has satisfied trigger and
29   * it was called less frequently that specified by its frequency ({@link DriveElement#getFreq()
30   * }).
31   *
32   * @see DriveCollection Useful to have an idea what is {@link DriveElement} for.
33   * @author HonzaH
34   */
35  public final class DriveElement extends PoshDummyElement<DriveElement, DriveCollection> implements INamedElement, IConditionElement<DriveElement> {
36  
37      /**
38       * Name of the drive. Unique in the DC.
39       */
40      private String name;
41      /**
42       * Trigger of this drive.
43       */
44      private final Trigger<DriveElement> trigger = new Trigger<DriveElement>(this);
45      /**
46       * Action of this drive.
47       */
48      private final TriggeredAction action;
49      /**
50       * If drive is called more frequenctly than specified by this frequency, it
51       * is not elegible to be processed during evaluation.
52       *
53       * @deprecated XXX: Not used in editor, maybe remove later
54       */
55      @Deprecated
56      private Freq freq;
57      /**
58       * Comment about this drive element.
59       *
60       * @deprecated XXX: Not used in editor, maybe remove later
61       */
62      @Deprecated
63      private String comment;
64      /**
65       * Property name for name of a drive
66       */
67      public static final String deName = "deName";
68      /**
69       * Data flavor of drive, used in drag-and-drop
70       */
71      public static final DataFlavor dataFlavor = new DataFlavor(DriveElement.class, "drive-element");
72  
73      /**
74       * Create a new DriveElement
75       *
76       * @param name name of drive element
77       * @param triggerSenses Senses that will form the trigger.
78       * @param actionCall action that will be called if driver is eligible and
79       * its trigger is satisfied.
80       */
81      DriveElement(String name, List<Sense> triggerSenses, PrimitiveCall actionCall, Freq freq, String comment) {
82          assert name != null;
83          this.name = name;
84  
85          assert freq != null;
86          this.freq = freq;
87  
88          assert comment != null;
89          this.comment = comment;
90  
91          for (Sense triggerSense : triggerSenses) {
92              assert !triggerSense.isChildOfParent();
93              trigger.add(triggerSense);
94          }
95  
96          this.action = LapElementsFactory.createAction(actionCall);
97          this.action.setParent(this);
98      }
99  
100     /**
101      * Get trigger of this drive.
102      */
103     public Trigger<DriveElement> getTrigger() {
104         return trigger;
105     }
106 
107     /**
108      * Get trigger of the element.
109      *
110      * @see #getTrigger()
111      * @return Trigger of element, never null.
112      */
113     @Override
114     public Trigger<DriveElement> getCondition() {
115         return getTrigger();
116     }
117 
118     /**
119      * Get action of this drive (will be performed if elegible, has satisfied
120      * trigger and highest priority).
121      *
122      * @return action of this drive
123      */
124     public TriggeredAction getAction() {
125         return action;
126     }
127 
128     @Override
129     public String toString() {
130         StringBuilder sb = new StringBuilder();
131 
132         sb.append('(');
133         sb.append(name);
134         if (!trigger.isEmpty()) {
135             sb.append(" (trigger ");
136             sb.append(trigger.toString());
137             sb.append(')');
138         }
139         sb.append(' ');
140         sb.append(this.action.toString());
141         sb.append(')');
142 
143         return sb.toString();
144     }
145 
146     @Override
147     public List<PoshElement> getChildDataNodes() {
148         List<PoshElement> children = new ArrayList<PoshElement>();
149         children.addAll(trigger);
150         children.add(this.action);
151 
152         return children;
153     }
154 
155     @Override
156     public String getName() {
157         return name;
158     }
159 
160     /**
161      * Set name of the drive to new name.
162      *
163      * @param newName New name of the drive.
164      * @throws InvalidNameException If name doesn't match {@link PoshDummyElement#IDENT_PATTERN}
165      * regexp.
166      */
167     public void setName(String newName) throws InvalidNameException, DuplicateNameException {
168         newName = newName.trim();
169         if (!newName.matches(IDENT_PATTERN)) {
170             throw InvalidNameException.create(newName);
171         }
172         DriveCollection dc = getParent();
173         for (DriveElement drive : dc.getDrives()) {
174             if (drive.getName().equals(newName) && drive != this) {
175                 throw new DuplicateNameException("There already is a drive with name " + newName);
176             }
177         }
178 
179 
180         String oldName = this.name;
181         this.name = newName;
182 
183         firePropertyChange(deName, oldName, newName);
184     }
185 
186     /**
187      * Becasue name of a drive is not used as reference in the plan, only call {@link #setName(java.lang.String)
188      * }.
189      *
190      * @param newName New name of drive.
191      */
192     @Override
193     public void rename(String newName) throws InvalidNameException, CycleException, DuplicateNameException {
194         setName(newName);
195     }
196 
197     @Override
198     public boolean moveChild(int newIndex, PoshElement child) {
199         throw new UnsupportedOperationException();
200     }
201 
202     @Override
203     public DataFlavor getDataFlavor() {
204         return dataFlavor;
205     }
206 
207     @Override
208     public LapType getType() {
209         return LapType.DRIVE_ELEMENT;
210     }
211 
212     /**
213      * Get how frequent can this drive be executed. Basically {@link PoshEngine}
214      * in each evaluation selects the drive with highest priority that has
215      * satisfied trigger and is being called less frequently, than specified by
216      * the frequency of the drive element.
217      *
218      * @return maximal frequency with which this drive can be called.
219      * @deprecated Part of original posh, not supported in editor.
220      */
221     @Deprecated
222     public Freq getFreq() {
223         return freq;
224     }
225 
226     /**
227      * Get comment of this drive.
228      *
229      * @return comment of the drive
230      * @deprecated Not supported in editor
231      */
232     @Deprecated
233     public String getComment() {
234         return comment;
235     }
236 }