001: package org.osbl.agent.model;
002:
003: import java.util.ArrayList;
004: import java.util.Hashtable;
005: import java.util.List;
006:
007: /**
008: * A rule consists principally of two key components: Conditions and Actions.
009: *
010: * Conditions define under which circumstances the Actions should be executed.
011: *
012: * This class serves as an coherent unit of Conditions and Actions and allows
013: * other operations such as giving the Rule a name and specify wether other
014: * users should be able to view and use the Rule or not.
015: *
016: * @see Condition, Action
017: * @author Sebastian Nozzi.
018: */
019: public class Rule {
020:
021: /** The name of the Rule. */
022: private String name;
023:
024: /** The meta information. */
025: private Hashtable<String, Object> metaInformation;
026:
027: /** Flag that indicates the public status of the Rule. */
028: private boolean isPublic;
029:
030: /** The creator user-id. */
031: private String creatorUser;
032:
033: /** The List of Conditions. */
034: private List<Condition> conditions;
035:
036: /** The List of Actions. */
037: private List<Action> actions;
038:
039: /**
040: * Instantiates a new Rule with the given name.
041: *
042: * @param name Name of the new Rule.
043: */
044: public Rule(String name) {
045: this ();
046: this .name = name;
047: }
048:
049: /**
050: * Instantiates a new Rule (with an empty name).
051: */
052: public Rule() {
053: name = "";
054: conditions = new ArrayList<Condition>();
055: actions = new ArrayList<Action>();
056: metaInformation = new Hashtable<String, Object>();
057: }
058:
059: /**
060: * Gets the meta-information repository.
061: *
062: * @return the meta-data repository
063: */
064: public Hashtable<String, Object> getMetaInformation() {
065: return metaInformation;
066: }
067:
068: /**
069: * Assigns a new meta-information repository.
070: *
071: * @param metaInformation the meta-data repository
072: */
073: public void setMetaInformation(
074: Hashtable<String, Object> metaInformation) {
075: this .metaInformation = metaInformation;
076: }
077:
078: /**
079: * Gets the list of Actions.
080: *
081: * To add/remove Actions to a Rule use this method to get the List and
082: * opperate directly on it.
083: *
084: * @return the list of Actions.
085: */
086: public List<Action> getActions() {
087: return actions;
088: }
089:
090: /**
091: * Sets a new Action list. The new list is used thus replacing all existing
092: * Actions.
093: *
094: * @param actions the list of Actions.
095: */
096: public void setActions(List<Action> actions) {
097: this .actions = actions;
098: }
099:
100: /**
101: * Gets the list of Conditions.
102: *
103: * To add/remove Conditions to a rule use this method to get the List and
104: * opperate directly on it.
105: *
106: * @return the list of Conditions.
107: */
108: public List<Condition> getConditions() {
109: return conditions;
110: }
111:
112: /**
113: * Sets a new Condition list. The new list is used thus replacing all
114: * existing Conditions.
115: *
116: * @param conditions the list of Conditions
117: */
118: public void setConditions(List<Condition> conditions) {
119: this .conditions = conditions;
120: }
121:
122: /**
123: * Gets the name of the Rule.
124: *
125: * @return the name of the Rule.
126: */
127: public String getName() {
128: return name;
129: }
130:
131: /**
132: * Sets the name of the Rule.
133: *
134: * @param name the new name.
135: */
136: public void setName(String name) {
137: this .name = name;
138: }
139:
140: /**
141: * Checks if is the Rule is marked as public.
142: *
143: * Public Rules are usable (but not editable) by other users in the
144: * AgentSystem.
145: *
146: * @return true, if the Rule is public.
147: */
148: public boolean isPublic() {
149: return isPublic;
150: }
151:
152: /**
153: * Marks the Rule as public.
154: *
155: * Public Rules are usable (but not editable) by other users in the
156: * AgentSystem.
157: *
158: * @param isPublic true if the Rule is to be published for all.
159: */
160: public void setPublic(boolean isPublic) {
161: this .isPublic = isPublic;
162: }
163:
164: /**
165: * Gets the creator user-id.
166: *
167: * The user-id is used for security purposes (for example an user can only
168: * edit/delete his/her own Rules in the system).
169: *
170: * @return the creator user-id
171: */
172: public String getCreatorUser() {
173: return creatorUser;
174: }
175:
176: /**
177: * Sets the creator user-id.
178: *
179: * The user-id is used for security purposes (for example an user can only
180: * edit/delete his/her own Rules in the system).
181: *
182: * @param user the new creator user-id.
183: */
184: public void setCreatorUser(String user) {
185: this .creatorUser = user;
186: }
187:
188: /**
189: * Evaluate Conditions from the internal List of Conditions.
190: *
191: * The evaluation stops as soon as one Condition evaluates to false.
192: *
193: * @param context the RuleContext used to perform the evaluation. It should have
194: * been populated with at least the target instance.
195: *
196: * @return true, if all Conditions evaluated to true.
197: */
198: public boolean evaluateConditions(RuleContext context) {
199:
200: int i = 1;
201:
202: // Lazily evaluate conditions, this is, stop as soon as one
203: // evaluates to "false"
204: for (Condition condition : conditions) {
205:
206: // As soon as one evaluates to "false" the whole evaluation is
207: // "false"
208: if (condition.evaluate(context) == false) {
209: System.out
210: .println("Condition evaluated to FALSE, exiting.");
211: return false;
212: }
213: System.out.println("Condition evaluated to TRUE.");
214: i++;
215: }
216:
217: // At this point all conditions evaluated to "true"
218: return true;
219: }
220:
221: /**
222: * Execute all Actions of the internal list of Actions.
223: *
224: * @param context the RuleContext used to perform the evaluation. It should have
225: * been populated with at least the target instance.
226: */
227: public void executeActions(RuleContext context) {
228:
229: // Execute all actions, one after the other
230: for (Action action : actions) {
231: System.out.println("Executing Action.");
232: action.execute(context);
233: }
234: }
235:
236: /**
237: * If the Rule has a name, then it is used as String version, otherwise the
238: * default implementation is used.
239: *
240: * @return an user readable version, using the Rule's name, if available.
241: *
242: * @see java.lang.Object#toString()
243: */
244: public String toString() {
245: // If the name of the condition was set, return it...
246: if (name != null && name.equals("") == false)
247: return getName();
248: // ...otherwise use the standard implementation
249: else
250: return super .toString();
251: }
252:
253: /**
254: * Provides a better implementation than the default, comparing the fields and
255: * then performing "equals" on the Conditions and Actions.
256: *
257: * The included Conditions and Actions should also override "equals" and provide
258: * a better implementation.
259: *
260: * @param obj the obj
261: *
262: * @return true, if equals
263: *
264: * @see java.lang.Object#equals(java.lang.Object)
265: */
266: public boolean equals(Object obj) {
267:
268: if (obj instanceof Rule == false)
269: return false;
270:
271: Rule other = (Rule) obj;
272:
273: if (this == other)
274: return true;
275:
276: if (!name.equals(other.name))
277: return false;
278:
279: if (isPublic != other.isPublic)
280: return false;
281:
282: if (!creatorUser.equals(other.creatorUser))
283: return false;
284:
285: // Note that (Array)List has an "equals" implementation according
286: // to our needs, however, in order for it to work we need to provide
287: // suitable implementations for the Actions and Conditions ourselves.
288:
289: if (!actions.equals(other.actions))
290: return false;
291:
292: if (!conditions.equals(other.conditions))
293: return false;
294:
295: // The implementation of "equals" of the Hashtable ought to be
296: // good enough as we only store Strings in it.
297:
298: // By the way, this comparison will catch changes in fields that
299: // are populated by the DesingContexts... for example an
300: // Activity change, where applicable (for Tasks, for example).
301:
302: if (!metaInformation.equals(other.metaInformation))
303: return false;
304:
305: // If everything else fails... test succeeded, assume they are equal.
306:
307: return true;
308: }
309:
310: // TODO: Nobody seems to be using this method!
311: /**
312: * Runs the Rule for the given RuleContext.
313: *
314: * It does the same as calling "evaluateConditions" and if successfull calling
315: * "executeActions".
316: *
317: * @param rtc the rtc
318: */
319: public void run(RuleContext rtc) {
320:
321: boolean resultOfEvaluation = evaluateConditions(rtc);
322:
323: if (resultOfEvaluation)
324: executeActions(rtc);
325: }
326:
327: /**
328: * Convenience static method to properly compare two properties of an object,
329: * taking into account that any of them could be "null".
330: *
331: * It avoids potential NullPointerExceptions that can be caused by comparing properties
332: * using "equals".
333: *
334: * @param thisProperty one property
335: * @param otherProperty the other property
336: *
337: * @return true, if successful
338: */
339: public static boolean propertyEquals(Object this Property,
340: Object otherProperty) {
341:
342: return (thisProperty == null) ? otherProperty == null
343: : thisProperty.equals(otherProperty);
344: }
345: }
|