001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.workflow.spi.memory;
006:
007: import com.opensymphony.module.propertyset.PropertySet;
008: import com.opensymphony.module.propertyset.PropertySetManager;
009:
010: import com.opensymphony.workflow.query.WorkflowQuery;
011: import com.opensymphony.workflow.spi.*;
012:
013: import org.apache.commons.logging.Log;
014: import org.apache.commons.logging.LogFactory;
015:
016: import java.io.*;
017:
018: import java.util.*;
019:
020: /**
021: * Simple flat file implementation.
022: *
023: * Following properties are <b>required</b>:
024: * <ul>
025: * <li><b>storeFile</b> - the absolute path to the store file
026: (<i>ex:c:\workflow.store</i>)</li>
027: * </ul>
028: *
029: * @author <a href="mailto:gbort@msn.com">Guillaume Bort</a>
030: */
031: public class SerializableWorkflowStore extends MemoryWorkflowStore {
032: //~ Static fields/initializers /////////////////////////////////////////////
033:
034: protected static final Log log = LogFactory
035: .getLog(SerializableWorkflowStore.class);
036: static String storeFile;
037:
038: //~ Methods ////////////////////////////////////////////////////////////////
039:
040: public PropertySet getPropertySet(long entryId) {
041: PropertySet ps = (PropertySet) SerializableCache.getInstance().propertySetCache
042: .get(new Long(entryId));
043:
044: if (ps == null) {
045: ps = PropertySetManager.getInstance("serializable", null);
046: SerializableCache.getInstance().propertySetCache.put(
047: new Long(entryId), ps);
048: }
049:
050: return ps;
051: }
052:
053: public static void setStoreFile(String storeFile) {
054: SerializableWorkflowStore.storeFile = storeFile;
055: }
056:
057: public static String getStoreFile() {
058: return storeFile;
059: }
060:
061: public Step createCurrentStep(long entryId, int stepId,
062: String owner, Date startDate, Date dueDate, String status,
063: long[] previousIds) {
064: long id = SerializableCache.getInstance().globalStepId++;
065: SimpleStep step = new SimpleStep(id, entryId, stepId, 0, owner,
066: startDate, dueDate, null, status, previousIds, null);
067:
068: List currentSteps = (List) SerializableCache.getInstance().currentStepsCache
069: .get(new Long(entryId));
070:
071: if (currentSteps == null) {
072: currentSteps = new ArrayList();
073: SerializableCache.getInstance().currentStepsCache.put(
074: new Long(entryId), currentSteps);
075: }
076:
077: currentSteps.add(step);
078: SerializableCache.store();
079:
080: return step;
081: }
082:
083: public WorkflowEntry createEntry(String workflowName) {
084: long id = SerializableCache.getInstance().globalEntryId++;
085: SimpleWorkflowEntry entry = new SimpleWorkflowEntry(id,
086: workflowName, WorkflowEntry.CREATED);
087: SerializableCache.getInstance().entryCache.put(new Long(id),
088: entry);
089: SerializableCache.store();
090:
091: return entry;
092: }
093:
094: public List findCurrentSteps(long entryId) {
095: List currentSteps = (List) SerializableCache.getInstance().currentStepsCache
096: .get(new Long(entryId));
097:
098: if (currentSteps == null) {
099: currentSteps = new ArrayList();
100: SerializableCache.getInstance().currentStepsCache.put(
101: new Long(entryId), currentSteps);
102: }
103:
104: return currentSteps;
105: }
106:
107: public WorkflowEntry findEntry(long entryId) {
108: return (WorkflowEntry) SerializableCache.getInstance().entryCache
109: .get(new Long(entryId));
110: }
111:
112: public List findHistorySteps(long entryId) {
113: List historySteps = (List) SerializableCache.getInstance().historyStepsCache
114: .get(new Long(entryId));
115:
116: if (historySteps == null) {
117: historySteps = new ArrayList();
118: SerializableCache.getInstance().historyStepsCache.put(
119: new Long(entryId), historySteps);
120: }
121:
122: return historySteps;
123: }
124:
125: public void init(Map props) {
126: storeFile = (String) props.get("storeFile");
127:
128: // check whether the file denoted by the storeFile property is a normal file.
129: if (!new File(storeFile).isFile()) {
130: log
131: .fatal("storePath property should indicate a normal file");
132: }
133:
134: // check wheter the directory containing the storeFile exist
135: if (!new File(storeFile).getParentFile().exists()) {
136: log.fatal("directory " + new File(storeFile).getParent()
137: + " not found");
138: }
139: }
140:
141: public Step markFinished(Step step, int actionId, Date finishDate,
142: String status, String caller) {
143: List currentSteps = (List) SerializableCache.getInstance().currentStepsCache
144: .get(new Long(step.getEntryId()));
145:
146: for (Iterator iterator = currentSteps.iterator(); iterator
147: .hasNext();) {
148: SimpleStep theStep = (SimpleStep) iterator.next();
149:
150: if (theStep.getId() == step.getId()) {
151: theStep.setStatus(status);
152: theStep.setActionId(actionId);
153: theStep.setFinishDate(finishDate);
154: theStep.setCaller(caller);
155:
156: return theStep;
157: }
158: }
159:
160: SerializableCache.store();
161:
162: return null;
163: }
164:
165: public void moveToHistory(Step step) {
166: List currentSteps = (List) SerializableCache.getInstance().currentStepsCache
167: .get(new Long(step.getEntryId()));
168:
169: List historySteps = (List) SerializableCache.getInstance().historyStepsCache
170: .get(new Long(step.getEntryId()));
171:
172: if (historySteps == null) {
173: historySteps = new ArrayList();
174: SerializableCache.getInstance().historyStepsCache.put(
175: new Long(step.getEntryId()), historySteps);
176: }
177:
178: SimpleStep simpleStep = (SimpleStep) step;
179:
180: for (Iterator iterator = currentSteps.iterator(); iterator
181: .hasNext();) {
182: Step currentStep = (Step) iterator.next();
183:
184: if (simpleStep.getId() == currentStep.getId()) {
185: iterator.remove();
186: historySteps.add(simpleStep);
187:
188: break;
189: }
190: }
191:
192: SerializableCache.store();
193: }
194: }
195:
196: class SerializableCache implements Serializable {
197: //~ Static fields/initializers /////////////////////////////////////////////
198:
199: private static transient SerializableCache instance;
200:
201: //~ Instance fields ////////////////////////////////////////////////////////
202:
203: HashMap currentStepsCache;
204: HashMap entryCache;
205: HashMap historyStepsCache;
206: HashMap propertySetCache;
207: long globalEntryId = 1;
208: long globalStepId = 1;
209:
210: //~ Constructors ///////////////////////////////////////////////////////////
211:
212: private SerializableCache() {
213: entryCache = new HashMap();
214: currentStepsCache = new HashMap();
215: historyStepsCache = new HashMap();
216: propertySetCache = new HashMap();
217: }
218:
219: //~ Methods ////////////////////////////////////////////////////////////////
220:
221: public List query(WorkflowQuery query) {
222: // not implemented
223: return Collections.EMPTY_LIST;
224: }
225:
226: static SerializableCache getInstance() {
227: if (instance == null) {
228: instance = load();
229: }
230:
231: return instance;
232: }
233:
234: static SerializableCache load() {
235: try {
236: FileInputStream fis = new FileInputStream(new File(
237: SerializableWorkflowStore.storeFile));
238: ObjectInputStream ois = new ObjectInputStream(fis);
239: SerializableCache o = (SerializableCache) ois.readObject();
240: fis.close();
241:
242: return o;
243: } catch (Exception e) {
244: SerializableWorkflowStore.log.fatal("cannot store in file "
245: + SerializableWorkflowStore.storeFile
246: + ". Create a new blank store.");
247: }
248:
249: return new SerializableCache();
250: }
251:
252: static void store() {
253: try {
254: FileOutputStream fos = new FileOutputStream(new File(
255: SerializableWorkflowStore.storeFile));
256: ObjectOutputStream oos = new ObjectOutputStream(fos);
257: oos.writeObject(getInstance());
258: fos.close();
259: } catch (Exception e) {
260: SerializableWorkflowStore.log.fatal("cannot store in file "
261: + SerializableWorkflowStore.storeFile + ".");
262: }
263: }
264: }
|