File Source: Action.java
1 /*
2 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 package com.dmdirc.actions;
24
25 import com.dmdirc.actions.interfaces.ActionType;
26 import com.dmdirc.actions.interfaces.ActionComponent;
27 import com.dmdirc.actions.interfaces.ActionComparison;
28 import com.dmdirc.config.prefs.PreferencesSetting;
29 import com.dmdirc.config.prefs.PreferencesType;
30 import com.dmdirc.logger.ErrorLevel;
31 import com.dmdirc.logger.Logger;
32 import com.dmdirc.util.ConfigFile;
33 import com.dmdirc.util.InvalidConfigFileException;
34
35 import java.io.File;
36 import java.io.IOException;
37 import java.io.Serializable;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43
44 /**
45 * Describes a single action.
46 *
47 * @author chris
48 */
49 public class Action extends ActionModel implements Serializable {
50
51 /**
52 * A version number for this class. It should be changed whenever the class
53 * structure is changed (or anything else that would prevent serialized
54 * objects being unserialized with the new class).
55 */
56 private static final long serialVersionUID = 1;
57
58 /** The domain name for condition trees. */
/*
P/P * Method: com.dmdirc.actions.Action__static_init
*
* Postconditions:
* DOMAIN_CONDITIONTREE != null
* DOMAIN_FORMAT != null
* DOMAIN_METADATA != null
* DOMAIN_RESPONSE != null
* DOMAIN_TRIGGERS != null
*/
59 private static final String DOMAIN_CONDITIONTREE = "conditiontree".intern();
60 /** The domain name for format changes. */
61 private static final String DOMAIN_FORMAT = "format".intern();
62 /** The domain name for meta-data. */
63 private static final String DOMAIN_METADATA = "metadata".intern();
64 /** The domain name for response information. */
65 private static final String DOMAIN_RESPONSE = "response".intern();
66 /** The domain name for triggers. */
67 private static final String DOMAIN_TRIGGERS = "triggers".intern();
68
69 /** The location of the file we're reading/saving. */
70 private String location;
71
72 /** The config file we're using. */
73 protected ConfigFile config;
74
75 /**
76 * Creates a new instance of Action. The group and name specified must
77 * be the group and name of a valid action already saved to disk.
78 *
79 * @param group The group the action belongs to
80 * @param name The name of the action
81 */
82 public Action(final String group, final String name) {
/*
P/P * Method: void com.dmdirc.actions.Action(String, String)
*
* Preconditions:
* init'ed(com/dmdirc/Main.configdir)
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.HIGH)
* init'ed(com.dmdirc.logger.ErrorLevel.MEDIUM)
* init'ed(java.io.File.separator)
*
* Postconditions:
* com/dmdirc/Main.configdir == One-of{old com/dmdirc/Main.configdir, &java.lang.StringBuilder:toString(...)}
* com/dmdirc/Main.configdir != null
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* java.lang.StringBuilder:toString(...)._tainted == 0
* this.conditions == &new ArrayList(ActionModel#1)
* init'ed(this.config)
* this.group == group
* init'ed(this.group)
* this.location == &java.lang.StringBuilder:toString(...)
* this.name == name
* ...
*/
83 super(group, name);
84
85 location = ActionManager.getDirectory() + group + File.separator + name;
86
87 try {
88 config = new ConfigFile(location);
89 config.read();
90 loadActionFromConfig();
91 } catch (InvalidConfigFileException ex) {
92 // This isn't a valid config file. Maybe it's a properties file?
93 Logger.userError(ErrorLevel.MEDIUM, "Unable to parse action file: "
94 + group + "/" + name + ": " + ex.getMessage());
95 } catch (IOException ex) {
96 Logger.userError(ErrorLevel.HIGH, "I/O error when loading action: "
97 + group + "/" + name + ": " + ex.getMessage());
98 }
99 }
100
101 /**
102 * Creates a new instance of Action with the specified properties and saves
103 * it to disk.
104 *
105 * @param group The group the action belongs to
106 * @param name The name of the action
107 * @param triggers The triggers to use
108 * @param response The response to use
109 * @param conditions The conditions to use
110 * @param newFormat The new formatter to use
111 */
112 public Action(final String group, final String name,
113 final ActionType[] triggers, final String[] response,
114 final List<ActionCondition> conditions, final String newFormat) {
/*
P/P * Method: void com.dmdirc.actions.Action(String, String, ActionType[], String[], List, String)
*
* Preconditions:
* conditions != null
* (soft) init'ed(com/dmdirc/ServerManager.me)
*
* Postconditions:
* com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
* java.lang.StringBuilder:toString(...)._tainted == 0
* new ConditionTree(readTerm#1)._tainted == 0
* init'ed(this.conditionTree)
* init'ed(this.conditions)
* init'ed(this.config)
* init'ed(this.group)
* init'ed(this.location)
* init'ed(this.modified)
* init'ed(this.name)
* ...
*/
115 this(group, name, triggers, response, conditions,
116 ConditionTree.createConjunction(conditions.size()), newFormat);
117 }
118
119 /**
120 * Creates a new instance of Action with the specified properties and saves
121 * it to disk.
122 *
123 * @param group The group the action belongs to
124 * @param name The name of the action
125 * @param triggers The triggers to use
126 * @param response The response to use
127 * @param conditions The conditions to use
128 * @param conditionTree The condition tree to use
129 * @param newFormat The new formatter to use
130 */
131 public Action(final String group, final String name,
132 final ActionType[] triggers, final String[] response,
133 final List<ActionCondition> conditions,
134 final ConditionTree conditionTree, final String newFormat) {
/*
P/P * Method: void com.dmdirc.actions.Action(String, String, ActionType[], String[], List, ConditionTree, String)
*
* Preconditions:
* init'ed(com/dmdirc/actions/ActionManager.killSwitch)
* init'ed(com/dmdirc/Main.configdir)
* response != null
* triggers != null
* (soft) com.dmdirc.actions.CoreActionType__static_init.new CoreActionType(CoreActionType__static_init#71).type != null
* (soft) conditions init'ed
* (soft) init'ed(com/dmdirc/ServerManager.me)
* (soft) init'ed(response[...])
* (soft) triggers.length <= 232-1
* (soft) init'ed(triggers[...])
*
* Presumptions:
* init'ed(java.io.File.separator)
*
* Postconditions:
* com/dmdirc/Main.configdir == One-of{old com/dmdirc/Main.configdir, &java.lang.StringBuilder:toString(...)}
* com/dmdirc/Main.configdir != null
* init'ed(com/dmdirc/ServerManager.me)
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* java.lang.StringBuilder:toString(...)._tainted == 0
* this.conditionTree == conditionTree
* init'ed(this.conditionTree)
* this.conditions == conditions
* init'ed(this.conditions)
* init'ed(this.config)
* ...
*/
135 super(group, name, triggers, response, conditions, conditionTree, newFormat);
136
137 final String dir = ActionManager.getDirectory() + group + File.separator;
138 location = dir + name;
139
140 new File(dir).mkdirs();
141
142 ActionManager.processEvent(CoreActionType.ACTION_CREATED, null, this);
143
144 save();
145
146 ActionManager.registerAction(this);
147 }
148
149 /**
150 * Loads this action from the config instance.
151 */
152 protected void loadActionFromConfig() {
/*
P/P * Method: void loadActionFromConfig()
*
* Preconditions:
* this.config != null
* (soft) init'ed(com/dmdirc/ServerManager.me)
* (soft) init'ed(this.triggers[0])
* (soft) init'ed(this.triggers[...])
* (soft) this.conditions != null
* (soft) init'ed(this.group)
* (soft) init'ed(this.name)
*
* Presumptions:
* com.dmdirc.util.ConfigFile:getFlatDomain(...)@154 != null
* com.dmdirc.util.ConfigFile:getFlatDomain(...)@163 != null
* com.dmdirc.util.ConfigFile:getFlatDomain(...)@166 != null
* com.dmdirc.util.ConfigFile:getFlatDomain(...)@175 != null
* com.dmdirc.util.ConfigFile:getFlatDomain(...)@185 != null
* ...
*
* Postconditions:
* init'ed(com/dmdirc/ServerManager.me)
* possibly_updated(this.conditionTree)
* possibly_updated(this.newFormat)
* this.response == One-of{old this.response, &new String[](loadActionFromConfig#1)}
* init'ed(this.response[...])
* this.triggers == One-of{&new ActionType[](loadTriggers#1), old this.triggers}
* init'ed(this.triggers[0])
* init'ed(this.triggers[...])
* new ActionType[](loadTriggers#1) num objects <= 1
* init'ed(new ActionType[](loadTriggers#1).length)
* ...
*
* Test Vectors:
* com.dmdirc.util.ConfigFile:isFlatDomain(...)@153: {0}, {1}
* com.dmdirc.util.ConfigFile:isFlatDomain(...)@162: {0}, {1}
* com.dmdirc.util.ConfigFile:isFlatDomain(...)@174: {0}, {1}
* com.dmdirc.util.ConfigFile:isFlatDomain(...)@185: {0}, {1}
* com.dmdirc.util.ConfigFile:isKeyDomain(...)@179: {0}, {1}
* java.util.Iterator:hasNext(...)@166: {0}, {1}
* java.util.List:size(...)@185: {-231..0}, {1..232-1}
*/
153 if (config.isFlatDomain(DOMAIN_TRIGGERS)) {
154 if (!loadTriggers(config.getFlatDomain(DOMAIN_TRIGGERS))) {
155 return;
156 }
157 } else {
158 error("No trigger specified");
159 return;
160 }
161
162 if (config.isFlatDomain(DOMAIN_RESPONSE)) {
163 response = new String[config.getFlatDomain(DOMAIN_RESPONSE).size()];
164
165 int i = 0;
166 for (String line: config.getFlatDomain(DOMAIN_RESPONSE)) {
167 response[i++] = line;
168 }
169 } else {
170 error("No response specified");
171 return;
172 }
173
174 if (config.isFlatDomain(DOMAIN_FORMAT)) {
175 newFormat = config.getFlatDomain(DOMAIN_FORMAT).size() == 0 ? "" :
176 config.getFlatDomain(DOMAIN_FORMAT).get(0);
177 }
178
179 for (int cond = 0; config.isKeyDomain("condition " + cond); cond++) {
180 if (!readCondition(config.getKeyDomain("condition " + cond))) {
181 return;
182 }
183 }
184
185 if (config.isFlatDomain(DOMAIN_CONDITIONTREE)
186 && config.getFlatDomain(DOMAIN_CONDITIONTREE).size() > 0) {
187 conditionTree = ConditionTree.parseString(
188 config.getFlatDomain(DOMAIN_CONDITIONTREE).get(0));
189
190 if (conditionTree == null) {
191 error("Unable to parse condition tree");
192 return;
193 }
194
195 if (conditionTree.getMaximumArgument() >= conditions.size()) {
196 error("Condition tree references condition "
197 + conditionTree.getMaximumArgument() + " but there are"
198 + " only " + conditions.size() + " conditions");
199 return;
200 }
201 }
202
203 ActionManager.registerAction(this);
204
205 checkMetaData();
206 }
207
208 /**
209 * Checks to see if this action contains group meta-data, and adds it to
210 * the group as appropriate.
211 */
212 private void checkMetaData() {
/*
P/P * Method: void checkMetaData()
*
* Preconditions:
* this.config != null
* (soft) init'ed(this.group)
*
* Presumptions:
* com.dmdirc.util.ConfigFile:getKeyDomain(...)@215 != null
* com.dmdirc.util.ConfigFile:getKeyDomain(...)@244 != null
* java.util.Map:get(...)@309 != null
* myGroup.settings != null
*
* Test Vectors:
* com.dmdirc.util.ConfigFile:isKeyDomain(...)@213: {0}, {1}
* com.dmdirc.util.ConfigFile:isKeyDomain(...)@242: {0}, {1}
* java.util.Map:containsKey(...)@217: {0}, {1}
* java.util.Map:containsKey(...)@221: {0}, {1}
* java.util.Map:containsKey(...)@225: {0}, {1}
* java.util.Map:containsKey(...)@233: {0}, {1}
* java.util.Map:containsKey(...)@246: {0}, {1}
*/
213 if (config.isKeyDomain(DOMAIN_METADATA)) {
214 final ActionGroup myGroup = ActionManager.getGroup(group);
215 final Map<String, String> data = config.getKeyDomain(DOMAIN_METADATA);
216
217 if (data.containsKey("description")) {
218 myGroup.setDescription(data.get("description"));
219 }
220
221 if (data.containsKey("author")) {
222 myGroup.setAuthor(data.get("author"));
223 }
224
225 if (data.containsKey("version")) {
226 try {
227 myGroup.setVersion(Integer.parseInt(data.get("version")));
228 } catch (NumberFormatException ex) {
229 // Do nothing
230 }
231 }
232
233 if (data.containsKey("component")) {
234 try {
235 myGroup.setComponent(Integer.parseInt(data.get("component")));
236 } catch (NumberFormatException ex) {
237 // Do nothing
238 }
239 }
240 }
241
242 for (int i = 0; config.isKeyDomain("setting " + i); i++) {
243 final ActionGroup myGroup = ActionManager.getGroup(group);
244 final Map<String, String> data = config.getKeyDomain("setting " + i);
245
246 if (data.containsKey("type") && data.containsKey("setting")
247 && data.containsKey("title") && data.containsKey("default")
248 && data.containsKey("tooltip")) {
249 ActionManager.registerDefault(data.get("setting"), data.get("default"));
250 myGroup.getSettings().put(data.get("setting"), new PreferencesSetting(
251 PreferencesType.valueOf(data.get("type")), "actions",
252 data.get("setting"), data.get("title"), data.get("tooltip")));
253 }
254 }
255 }
256
257 /**
258 * Loads a list of triggers with the specified names.
259 *
260 * @param newTriggers A list of trigger names
261 * @return True if all triggers are valid and compatible, false otherwise.
262 */
263 private boolean loadTriggers(final List<String> newTriggers) {
/*
P/P * Method: bool loadTriggers(List)
*
* Preconditions:
* newTriggers != null
* (soft) init'ed(this.group)
* (soft) init'ed(this.name)
*
* Presumptions:
* java.util.List:size(...)@264 >= 0
* this.triggers[i].type != null
*
* Postconditions:
* init'ed(return_value)
* this.triggers == &new ActionType[](loadTriggers#1)
* possibly_updated(this.triggers[0])
* possibly_updated(this.triggers[...])
* new ActionType[](loadTriggers#1) num objects == 1
* this.triggers.length <= 232-1
* init'ed(this.triggers[0])
*
* Test Vectors:
* java.lang.Object:equals(...)@272: {1}, {0}
*/
264 triggers = new ActionType[newTriggers.size()];
265
266 for (int i = 0; i < triggers.length; i++) {
267 triggers[i] = ActionManager.getActionType(newTriggers.get(i));
268
269 if (triggers[i] == null) {
270 error("Invalid trigger specified: " + newTriggers.get(i));
271 return false;
272 } else if (i != 0 && !triggers[i].getType().equals(triggers[0].getType())) {
273 error("Triggers are not compatible");
274 return false;
275 }
276 }
277
278 return true;
279 }
280
281 /**
282 * Called to save the action.
283 */
284 public void save() {
/*
P/P * Method: void save()
*
* Preconditions:
* init'ed(this.modified)
* (soft) init'ed(com.dmdirc.actions.ConditionTree$1__static_init.new int[](ConditionTree$1__static_init#1)[...])
* (soft) com.dmdirc.actions.CoreActionType__static_init.new CoreActionType(CoreActionType__static_init#72).type != null
* (soft) init'ed(com/dmdirc/actions/ActionManager.killSwitch)
* (soft) init'ed(com/dmdirc/ServerManager.me)
* (soft) init'ed(this.conditionTree)
* (soft) init'ed(this.conditionTree.argument)
* (soft) init'ed(this.conditionTree.leftArg)
* (soft) this.conditionTree.op != null
* (soft) init'ed(this.conditionTree.rightArg)
* ...
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.HIGH)
* init'ed(com.dmdirc.logger.ErrorLevel.LOW)
* com.dmdirc.util.ConfigFile:getFlatDomain(...)@314 != null
* com.dmdirc.util.ConfigFile:getFlatDomain(...)@319 != null
* condition.comparison@323 != null
* ...
*
* Postconditions:
* com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
* init'ed(this.modified)
* new ArrayList(ServerManager#1) num objects == 0, if init'ed
* new ServerManager(getServerManager#1) num objects == 0, if init'ed
* new ServerManager(getServerManager#1).servers == null
*
* Test Vectors:
* this.modified: {1}, {0}
* this.conditionTree: Addr_Set{null}, Inverse{null}
* this.config: Addr_Set{null}, Inverse{null}
* this.newFormat: Addr_Set{null}, Inverse{null}
* this.triggers[...]: Inverse{null}, Addr_Set{null}
* com.dmdirc.util.ConfigFile:isKeyDomain(...)@343: {0}, {1}
* com.dmdirc.util.ConfigFile:isKeyDomain(...)@347: {0}, {1}
* condition.arg@323: {-231..-2, 0..232-1}, {-1}
* java.util.Iterator:hasNext(...)@323: {0}, {1}
*/
285 if (!isModified()) {
286 return;
287 }
288
289 final ConfigFile newConfig = new ConfigFile(location);
290
291 final List<String> triggerNames = new ArrayList<String>();
292 final List<String> responseLines = new ArrayList<String>();
293
294 for (ActionType trigger : triggers) {
295 if (trigger == null) {
296 Logger.appError(ErrorLevel.LOW, "ActionType was null",
297 new IllegalArgumentException("Triggers: "
298 + Arrays.toString(triggers)));
299 continue;
300 }
301
302 triggerNames.add(trigger.toString());
303 }
304
305 for (String line : response) {
306 responseLines.add(line);
307 }
308
309 newConfig.addDomain(DOMAIN_TRIGGERS, triggerNames);
310 newConfig.addDomain(DOMAIN_RESPONSE, responseLines);
311
312 if (conditionTree != null) {
313 newConfig.addDomain(DOMAIN_CONDITIONTREE, new ArrayList<String>());
314 newConfig.getFlatDomain(DOMAIN_CONDITIONTREE).add(conditionTree.toString());
315 }
316
317 if (newFormat != null) {
318 newConfig.addDomain(DOMAIN_FORMAT, new ArrayList<String>());
319 newConfig.getFlatDomain(DOMAIN_FORMAT).add(newFormat);
320 }
321
322 int i = 0;
323 for (ActionCondition condition : conditions) {
324 final Map<String, String> data = new HashMap<String, String>();
325
326 data.put("argument", String.valueOf(condition.getArg()));
327
328 if (condition.getArg() == -1) {
329 data.put("starget", condition.getStarget());
330 } else {
331 data.put("component", condition.getComponent().toString());
332 }
333
334 data.put("comparison", condition.getComparison().toString());
335 data.put("target", condition.getTarget());
336
337 newConfig.addDomain("condition " + i, data);
338 i++;
339 }
340
341 if (config != null) {
342 // Preserve any meta-data
343 if (config.isKeyDomain(DOMAIN_METADATA)) {
344 newConfig.addDomain(DOMAIN_METADATA, config.getKeyDomain(DOMAIN_METADATA));
345 }
346
347 for (i = 0; config.isKeyDomain("setting " + i); i++) {
348 newConfig.addDomain("setting " + i, config.getKeyDomain("setting " + i));
349 }
350 }
351
352 try {
353 newConfig.write();
354
355 resetModified();
356 } catch (IOException ex) {
357 Logger.userError(ErrorLevel.HIGH, "I/O error when saving action: "
358 + group + "/" + name + ": " + ex.getMessage());
359 }
360 ActionManager.processEvent(CoreActionType.ACTION_UPDATED, null, this);
361 }
362
363 /**
364 * Reads a condition from the specified configuration section.
365 *
366 * @param data The relevant section of the action configuration
367 * @return True if the condition is valid, false otherwise
368 */
369 private boolean readCondition(final Map<String,String> data) {
/*
P/P * Method: bool readCondition(Map)
*
* Preconditions:
* data != null
* (soft) this.conditions != null
* (soft) init'ed(this.group)
* (soft) init'ed(this.name)
* (soft) this.triggers != null
* (soft) this.triggers.length >= 1
* (soft) this.triggers[0] != null
* (soft) this.triggers[0].type != null
*
* Presumptions:
* appliesTo(...)@414 != null
* getType(...)@385 != getType(...)
* java.util.Map:get(...)@408 != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* java.lang.Integer:parseInt(...)@379: {-231..-2}, {0..232-2}, {-1}
* java.lang.Object:equals(...)@414: {0}, {1}
* java.lang.Object:equals(...)@414: {1}, {0}
* java.util.Map:get(...)@393: Inverse{null}, Addr_Set{null}
* java.util.Map:get(...)@422: Inverse{null}, Addr_Set{null}
*/
370 int arg = 0;
371 ActionComponent component = null;
372 ActionComparison comparison = null;
373 String target = "";
374 String starget = null;
375
376 // ------ Read the argument
377
378 try {
379 arg = Integer.parseInt(data.get("argument"));
380 } catch (NumberFormatException ex) {
381 error("Invalid argument number specified: " + data.get("argument"));
382 return false;
383 }
384
385 if (arg < -1 || arg >= triggers[0].getType().getArity()) {
386 error("Invalid argument number specified: " + arg);
387 return false;
388 }
389
390 // ------ Read the component or the source
391
392 if (arg == -1) {
393 starget = data.get("starget");
394
395 if (starget == null) {
396 error("No starget specified");
397 return false;
398 }
399 } else {
400 component = readComponent(data, arg);
401 if (component == null) {
402 return false;
403 }
404 }
405
406 // ------ Read the comparison
407
408 comparison = ActionManager.getActionComparison(data.get("comparison"));
409 if (comparison == null) {
410 error("Invalid comparison specified: " + data.get("comparison"));
411 return false;
412 }
413
414 if ((arg != -1 && !comparison.appliesTo().equals(component.getType()))
415 || (arg == -1 && !comparison.appliesTo().equals(String.class))) {
416 error("Comparison cannot be applied to specified component: " + data.get("comparison"));
417 return false;
418 }
419
420 // ------ Read the target
421
422 target = data.get("target");
423
424 if (target == null) {
425 error("No target specified for condition");
426 return false;
427 }
428
429 if (arg == -1) {
430 conditions.add(new ActionCondition(starget, comparison, target));
431 } else {
432 conditions.add(new ActionCondition(arg, component, comparison, target));
433 }
434
435 return true;
436 }
437
438 /**
439 * Reads a component from the specified data section for the specified argument.
440 *
441 * @param data The relevant section of the action configuration
442 * @param arg The argument number that the component should apply to
443 * @return The corresponding ActionComponent, or null if the specified
444 * component is invalid.
445 */
446 private ActionComponent readComponent(final Map<String, String> data, final int arg) {
/*
P/P * Method: ActionComponent readComponent(Map, int)
*
* Preconditions:
* data != null
* (soft) arg >= 0
* (soft) init'ed(this.group)
* (soft) init'ed(this.name)
* (soft) this.triggers != null
* (soft) this.triggers.length >= 1
* (soft) this.triggers[0] != null
* (soft) this.triggers[0].type != null
*
* Presumptions:
* appliesTo(...)@467 != null
* getArgTypes(...).length@454 >= 1
* arg < getArgTypes(...).length@454
* getArgTypes(...).length@467 >= 1
* arg < getArgTypes(...).length@467
* ...
*
* Postconditions:
* init'ed(return_value)
* new ActionComponentChain(readComponent#1) num objects <= 1
* possibly_updated(new ActionComponentChain(readComponent#1).components)
* new ArrayList(ActionComponentChain#1) num objects <= 1
*
* Test Vectors:
* java.lang.Object:equals(...)@467: {1}, {0}
* java.lang.String:indexOf(...)@450: {-231..-2, 0..232-1}, {-1}
*/
447 final String componentName = data.get("component");
448 ActionComponent component;
449
450 if (componentName.indexOf('.') == -1) {
451 component = ActionManager.getActionComponent(componentName);
452 } else {
453 try {
454 component = new ActionComponentChain(triggers[0].getType().getArgTypes()[arg],
455 componentName);
456 } catch (IllegalArgumentException iae) {
457 error(iae.getMessage());
458 return null;
459 }
460 }
461
462 if (component == null) {
463 error("Unknown component: " + componentName);
464 return null;
465 }
466
467 if (!component.appliesTo().equals(triggers[0].getType().getArgTypes()[arg])) {
468 error("Component cannot be applied to specified arg in condition: " + componentName);
469 return null;
470 }
471
472 return component;
473 }
474
475 /**
476 * Raises a trivial error, informing the user of the problem.
477 *
478 * @param message The message to be raised
479 */
480 private void error(final String message) {
/*
P/P * Method: void error(String)
*
* Preconditions:
* init'ed(this.group)
* init'ed(this.name)
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.LOW)
*/
481 Logger.userError(ErrorLevel.LOW, "Error when parsing action: "
482 + group + "/" + name + ": " + message);
483 }
484
485 /** {@inheritDoc} */
486 @Override
487 public void setName(final String newName) {
/*
P/P * Method: void setName(String)
*
* Preconditions:
* init'ed(com/dmdirc/Main.configdir)
* init'ed(this.location)
* init'ed(this.group)
*
* Presumptions:
* init'ed(java.io.File.separator)
*
* Postconditions:
* com/dmdirc/Main.configdir == One-of{old com/dmdirc/Main.configdir, &java.lang.StringBuilder:toString(...)}
* com/dmdirc/Main.configdir != null
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* java.lang.StringBuilder:toString(...)._tainted == 0
* this.location == &java.lang.StringBuilder:toString(...)
* this.modified == 1
* this.name == newName
* init'ed(this.name)
*/
488 super.setName(newName);
489
490 new File(location).delete();
491 location = ActionManager.getDirectory() + group + File.separator + newName;
492
493 save();
494 }
495
496 /** {@inheritDoc} */
497 @Override
498 public void setGroup(final String newGroup) {
/*
P/P * Method: void setGroup(String)
*
* Preconditions:
* init'ed(com/dmdirc/Main.configdir)
* init'ed(this.location)
* init'ed(this.name)
*
* Presumptions:
* init'ed(java.io.File.separator)
*
* Postconditions:
* com/dmdirc/Main.configdir == One-of{old com/dmdirc/Main.configdir, &java.lang.StringBuilder:toString(...)}
* com/dmdirc/Main.configdir != null
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* java.lang.StringBuilder:toString(...)._tainted == 0
* this.group == newGroup
* init'ed(this.group)
* this.location == &java.lang.StringBuilder:toString(...)
* this.modified == 1
*/
499 super.setGroup(newGroup);
500
501 new File(location).delete();
502
503 final String dir = ActionManager.getDirectory() + group + File.separator;
504 location = dir + name;
505
506 new File(dir).mkdirs();
507
508 save();
509 }
510
511 /**
512 * Deletes this action.
513 */
514 public void delete() {
/*
P/P * Method: void delete()
*
* Preconditions:
* init'ed(com/dmdirc/actions/ActionManager.killSwitch)
* init'ed(this.group)
* init'ed(this.location)
* init'ed(this.name)
* (soft) com.dmdirc.actions.CoreActionType__static_init.new CoreActionType(CoreActionType__static_init#73).type != null
* (soft) init'ed(com/dmdirc/ServerManager.me)
*
* Postconditions:
* com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
* new ArrayList(ServerManager#1) num objects == undefined
* new ArrayList(ServerManager#1) num objects == 0, if init'ed
* new ServerManager(getServerManager#1) num objects == new ArrayList(ServerManager#1) num objects
* new ServerManager(getServerManager#1).servers == undefined
* new ServerManager(getServerManager#1).servers == null
*/
515 ActionManager.processEvent(CoreActionType.ACTION_DELETED, null, getGroup(), getName());
516 new File(location).delete();
517 }
518
519 /** {@inheritDoc} */
520 @Override
521 public String toString() {
/*
P/P * Method: String toString()
*
* Preconditions:
* init'ed(this.conditions)
* init'ed(this.group)
* init'ed(this.location)
* init'ed(this.name)
* init'ed(this.newFormat)
* init'ed(this.response)
* init'ed(this.triggers)
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == this.location._tainted | this.conditions._tainted | this.group._tainted | this.name._tainted | One-of{this.conditions._tainted | this.group._tainted | this.name._tainted, this.newFormat._tainted}
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* return_value == &java.lang.StringBuilder:toString(...)
*/
522 final String parent = super.toString();
523
524 return parent.substring(0, parent.length() - 1)
525 + ",location=" + location + "]";
526 }
527
528 }
SofCheck Inspector Build Version : 2.17854
| Action.java |
2009-Jun-25 01:54:24 |
| Action.class |
2009-Sep-02 17:04:17 |