001: package org.osbl.agent.logic;
002:
003: import java.beans.XMLDecoder;
004: import java.beans.XMLEncoder;
005: import java.io.BufferedInputStream;
006: import java.io.ByteArrayOutputStream;
007: import java.io.File;
008: import java.io.FileInputStream;
009: import java.io.FileNotFoundException;
010: import java.io.FileOutputStream;
011: import java.io.IOException;
012: import java.io.UnsupportedEncodingException;
013: import java.util.ArrayList;
014: import java.util.List;
015:
016: import org.concern.Controller;
017: import org.concern.ControllerLookup;
018: import org.concern.model.Process;
019: import org.osbl.agent.model.Rule;
020:
021: /**
022: * The AgentSystem class serves as the central repository for Rules. There is only one AgentSystem
023: * instance per OSBL installation, using the singleton pattern. It is responsible for storing the Rules and
024: * offering basic operations for them.
025: *
026: * The Rules in memory are kept synchronized with a persistent storage. Currently the persistence
027: * mechanism is accomplished by serializing to an XML file and reading it back again.
028: * The same XML framework is used for importing and exporting individual Rules.
029: *
030: * The AgentSystem object provides basic operations for adding, retrieving and deleting Rules. Being a
031: * singleton object potentially accessible by many processes at the same time, those operations are all
032: * thread-safe (“synchronized�).
033: *
034: * Rules are stored in an non-hierarchical indiscriminate manner. The AgentSystem class knows nothing
035: * about Contexts. It is up to the callee to implement the corresponding recognition and filtering
036: * algorithms.
037: *
038: * @author Sebastian Nozzi.
039: */
040: public class AgentSystem {
041:
042: /** The activity user rules. */
043: private List<Rule> rules;
044:
045: /** The process list. */
046: private ArrayList<Process> processList;
047:
048: /** The singleton instance. */
049: private static AgentSystem singletonInstance = null;
050:
051: /**
052: * Instantiates a new agent system.
053: */
054: private AgentSystem() {
055:
056: rules = new ArrayList<Rule>();
057:
058: // xstream = new XStream(new DomDriver());
059:
060: populateProcessList();
061:
062: loadRules();
063:
064: }
065:
066: /**
067: * Gets the singleton instance.
068: *
069: * @return the singleton instance
070: */
071: public static AgentSystem getSingletonInstance() {
072:
073: // Create the singleton instance
074: if (singletonInstance == null)
075: singletonInstance = new AgentSystem();
076:
077: return singletonInstance;
078: }
079:
080: /**
081: * Returns all Rules in the system.
082: *
083: * @return all the Rules.
084: */
085: public synchronized List<Rule> getRules() {
086: return rules;
087: }
088:
089: /**
090: * Gets the Rules that a given user has created.
091: *
092: * @param user the user-id.
093: *
094: * @return the Rules for that user-id.
095: */
096: public synchronized List<Rule> getRulesForUser(String user) {
097:
098: return getRulesForUser(user, false);
099: }
100:
101: /**
102: * Gets the all published Rules from other users but the one specified.
103: *
104: * @param notThisUser the user that is to be avoided.
105: *
106: * @return the public Rules for all other users but the one specified.
107: */
108: public synchronized List<Rule> getPublicRulesOfOthers(
109: String notThisUser) {
110:
111: List<Rule> allOthers = getRulesForUser(notThisUser, true);
112: List<Rule> publicOthers = new ArrayList<Rule>();
113:
114: for (Rule aRule : allOthers) {
115: if (aRule.isPublic())
116: publicOthers.add(aRule);
117: }
118:
119: return publicOthers;
120: }
121:
122: /**
123: * Either gets the Rules for one user, or all the Rules except for that user.
124: *
125: * @param userId the user-id.
126: * @param avoidUser whether to avoid that user or not.
127: *
128: * @return the Rules collected.
129: */
130: protected synchronized List<Rule> getRulesForUser(String userId,
131: boolean avoidUser) {
132:
133: List<Rule> result = new ArrayList<Rule>();
134:
135: for (Rule aRule : rules) {
136: if (aRule.getCreatorUser().equals(userId) == (!avoidUser))
137: result.add(aRule);
138: }
139:
140: return result;
141: }
142:
143: /**
144: * Adds a Rule into the system.
145: *
146: * @param newRule the new Rule.
147: */
148: public synchronized void addRule(Rule newRule) {
149:
150: rules.add(newRule);
151:
152: saveRules();
153: }
154:
155: /**
156: * In case Rules are indirectly modified (outside this class, which is very common)
157: * and the client wants to make sure that those changes are persistent and reflected
158: * across the system, it should call this method.
159: */
160: public synchronized void updateRules() {
161: saveRules();
162: }
163:
164: /**
165: * Removes a Rule from the system.
166: *
167: * @param ruleToDelete the rule to delete.
168: */
169: public synchronized void removeRule(Rule ruleToDelete) {
170:
171: /*boolean result = */
172: rules.remove(ruleToDelete);
173:
174: saveRules();
175: }
176:
177: /**
178: * Save the Rules to a persistent store.
179: */
180: protected void saveRules() {
181:
182: FileOutputStream fileOut;
183:
184: try {
185: fileOut = new FileOutputStream("rules.xml");
186:
187: XMLEncoder xmlEncoder = new XMLEncoder(fileOut);
188:
189: xmlEncoder.writeObject(rules);
190:
191: xmlEncoder.close();
192:
193: fileOut.close();
194:
195: } catch (FileNotFoundException e) {
196: // TODO Auto-generated catch block
197: e.printStackTrace();
198: } catch (IOException e) {
199: // TODO Auto-generated catch block
200: e.printStackTrace();
201: }
202: }
203:
204: /**
205: * Provides a temporary file with an exported Rule.
206: *
207: * @param rule the Rule for which the file is to be generated.
208: *
209: * @return a temporary file with an exported Rule.
210: */
211: public File tempRuleFile(Rule rule) {
212:
213: File tempFile = null;
214:
215: try {
216: tempFile = File.createTempFile("temporary-osbl-agent",
217: ".xml");
218: tempFile.deleteOnExit();
219:
220: FileOutputStream fileOutStream = new FileOutputStream(
221: tempFile);
222:
223: XMLEncoder xmlEncoder = new XMLEncoder(fileOutStream);
224:
225: xmlEncoder.writeObject(rule);
226:
227: xmlEncoder.close();
228:
229: fileOutStream.close();
230:
231: } catch (IOException e) {
232: // TODO Auto-generated catch block
233: e.printStackTrace();
234: }
235:
236: return tempFile;
237: }
238:
239: /**
240: * Provides an XML-serialized version of a Rule.
241: *
242: * @param rule the Rule to be serialized.
243: *
244: * @return the resulting XML String.
245: */
246: public String ruleAsXML(Rule rule) {
247:
248: ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
249:
250: XMLEncoder xmlEncoder = new XMLEncoder(outputStream);
251:
252: xmlEncoder.writeObject(rule);
253:
254: xmlEncoder.close();
255:
256: try {
257: return new String(outputStream.toByteArray(), "UTF-8");
258: } catch (UnsupportedEncodingException e) {
259: e.printStackTrace();
260: return "";
261: }
262: }
263:
264: /**
265: * From a given XML document it reconstructs a Rule object.
266: *
267: * @param ruleXMLFile the XML file containing a Rule.
268: *
269: * @return the generated Rule.
270: */
271: public Rule XMLToRule(File ruleXMLFile) {
272:
273: try {
274:
275: XMLDecoder xmlDecoder = new XMLDecoder(
276: new BufferedInputStream(new FileInputStream(
277: ruleXMLFile)));
278:
279: Rule newRule = (Rule) xmlDecoder.readObject();
280:
281: xmlDecoder.close();
282:
283: return newRule;
284:
285: } catch (ClassCastException e) {
286: return null;
287: } catch (FileNotFoundException e) {
288: return null;
289: }
290: }
291:
292: /**
293: * Loads all Rules from the persistent store.
294: */
295: protected void loadRules() {
296:
297: FileInputStream fileIn;
298:
299: try {
300: fileIn = new FileInputStream("rules.xml");
301:
302: XMLDecoder xmlDecoder = new XMLDecoder(fileIn);
303:
304: rules = (List<Rule>) xmlDecoder.readObject();
305:
306: xmlDecoder.close();
307:
308: fileIn.close();
309:
310: } catch (Exception e) {
311: e.printStackTrace();
312: }
313: }
314:
315: /**
316: * Populates the (con:cern) Process list.
317: */
318: protected void populateProcessList() {
319:
320: // This will store all available Processes
321: processList = new ArrayList<Process>();
322:
323: // Get the singleton ControllerLookup singletonInstance.
324: ControllerLookup controllerLookup = ControllerLookup
325: .getInstance();
326:
327: // With all controller names...
328: for (String controllerName : controllerLookup
329: .getControllerNames()) {
330: // ...get the real controller...
331: Controller controller = controllerLookup
332: .getController(controllerName);
333:
334: // ...and from it the Process, and add it to our list.
335: processList.add(controller.getProcess());
336: }
337: }
338:
339: /**
340: * Convenience method to get the list of running (con:cern) Processes.
341: * Used by the DesignContexts that interact with con:cern.
342: *
343: * @return the list of Processes.
344: */
345: public ArrayList<Process> getProcessList() {
346: return processList;
347: }
348:
349: }
|