001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.engine.persistence.memory;
046:
047: import org.apache.commons.logging.Log;
048: import org.apache.commons.logging.LogFactory;
049: import org.obe.client.api.model.ActivityInstanceAttributes;
050: import org.obe.client.api.model.ProcessInstanceAttributes;
051: import org.obe.client.api.repository.ObjectNotFoundException;
052: import org.obe.client.api.repository.RepositoryException;
053: import org.obe.engine.repository.AbstractRepository;
054: import org.obe.engine.util.AttributeFilter;
055: import org.obe.spi.model.*;
056: import org.obe.spi.service.ApplicationEventBroker;
057: import org.obe.spi.service.InstanceRepository;
058: import org.obe.spi.service.ServiceManager;
059: import org.wfmc.audit.WMAAuditEntry;
060: import org.wfmc.wapi.WMFilter;
061:
062: import java.util.*;
063:
064: /**
065: * Provides caching and persistence services for process instances.
066: * This includes process instances, workflow relevant data, activity
067: * instances, work items; also attributes for process instance,
068: * activity instance, and work items.
069: *
070: * @author Anthony Eden
071: * @author Adrian Price
072: */
073: public class BasicInstanceRepository extends AbstractRepository
074: implements InstanceRepository {
075:
076: private static final Log _logger = LogFactory
077: .getLog(BasicInstanceRepository.class);
078: private static final Integer PROCESS_INSTANCE_TYPE = new Integer(
079: AttributedEntity.PROCESS_INSTANCE_TYPE);
080: private static final Integer ACTIVITY_INSTANCE_TYPE = new Integer(
081: AttributedEntity.ACTIVITY_INSTANCE_TYPE);
082: private static final Integer WORKITEM_TYPE = new Integer(
083: AttributedEntity.WORKITEM_TYPE);
084: private static final WMFilter[] EMPTY_FILTERS = {};
085: private long _lastProcessInstanceId;
086: private long _lastActivityInstanceId;
087: private long _lastWorkItemId;
088: private final Map _processInstances = new HashMap();
089: private final Map _activityInstances = new HashMap();
090: private final Map _activityInstancesByDefnId = new HashMap();
091: private final Map _workItems = new HashMap();
092: private final Map _attributeInstances = new HashMap();
093:
094: private static class TripleKey {
095: final Object key1;
096: final Object key2;
097: final Object key3;
098:
099: TripleKey(Object key1) {
100: this .key1 = key1;
101: key2 = key3 = null;
102: }
103:
104: TripleKey(Object key1, Object key2) {
105: this .key1 = key1;
106: this .key2 = key2;
107: key3 = null;
108: }
109:
110: TripleKey(Object key1, Object key2, Object key3) {
111: this .key1 = key1;
112: this .key2 = key2;
113: this .key3 = key3;
114: }
115:
116: public boolean equals(Object obj) {
117: if (this == obj)
118: return true;
119: if (!(obj instanceof TripleKey))
120: return false;
121:
122: TripleKey that = (TripleKey) obj;
123: return key1.equals(that.key1)
124: && (key2 == null || that.key2 == null || key2
125: .equals(that.key2))
126: && (key3 == null || that.key3 == null || key3
127: .equals(that.key3));
128: }
129:
130: public int hashCode() {
131: return 29 * (29 * key1.hashCode() + key2.hashCode())
132: + (key3 == null ? 0 : key3.hashCode());
133: }
134: }
135:
136: public BasicInstanceRepository(ServiceManager svcMgr) {
137: super (svcMgr, null);
138: BasicAttributeInstance.setServiceManager(svcMgr);
139: }
140:
141: public synchronized void init() {
142: }
143:
144: public synchronized void exit() {
145: }
146:
147: public synchronized void store() {
148: }
149:
150: public void purge() throws RepositoryException {
151: ApplicationEventBroker eventBroker = _svcMgr
152: .getApplicationEventBroker();
153: String[] keys = new String[2];
154: for (Iterator iter = _processInstances.values().iterator(); iter
155: .hasNext();) {
156:
157: ProcessInstance processInstance = (ProcessInstance) iter
158: .next();
159: keys[0] = processInstance.getProcessDefinitionId();
160: keys[1] = processInstance.getProcessInstanceId();
161: eventBroker.unsubscribe(keys, false);
162: }
163: _processInstances.clear();
164: _activityInstances.clear();
165: _activityInstancesByDefnId.clear();
166: _workItems.clear();
167: _attributeInstances.clear();
168: }
169:
170: public ProcessInstance createProcessInstance(
171: String processDefinitionId,
172: String parentActivityInstanceId,
173: String processInstanceName, int priority, int state,
174: Date createdDate, Date startedDate, String[] participants)
175: throws RepositoryException {
176:
177: synchronized (_processInstances) {
178: ActivityInstance parentActivityInstance = null;
179: if (parentActivityInstanceId != null) {
180: parentActivityInstance = findActivityInstance(parentActivityInstanceId);
181: }
182:
183: String processInstanceId = String
184: .valueOf(_lastProcessInstanceId++);
185: ProcessInstance processInstance = new BasicProcessInstance(
186: processInstanceId, processDefinitionId,
187: parentActivityInstance);
188: processInstance.setName(processInstanceName);
189: processInstance.setPriority(priority);
190: processInstance.setState(state);
191: processInstance.setCreatedDate(createdDate);
192: processInstance.setStartedDate(startedDate);
193: processInstance.setParticipants(participants);
194:
195: _processInstances.put(processInstanceId, processInstance);
196:
197: return processInstance;
198: }
199: }
200:
201: public ProcessInstance findProcessInstance(String processInstanceId)
202: throws RepositoryException {
203:
204: ProcessInstance procInst = (ProcessInstance) _processInstances
205: .get(processInstanceId);
206: if (procInst == null)
207: throw new ObjectNotFoundException(processInstanceId);
208: return procInst;
209: }
210:
211: public ProcessInstance[] findProcessInstances(
212: String processDefinitionId, WMFilter filter,
213: boolean countFlag) throws RepositoryException {
214:
215: int n = 0;
216: if (processDefinitionId != null)
217: n++;
218: if (filter != null)
219: n++;
220: WMFilter[] filters = new WMFilter[n];
221: n = 0;
222: if (processDefinitionId != null) {
223: filters[n++] = new WMFilter(
224: ProcessInstanceAttributes.PROCESS_DEFINITION_ID,
225: WMFilter.EQ, processDefinitionId);
226: }
227: if (filter != null)
228: filters[n] = filter;
229: return (ProcessInstance[]) AttributeFilter.findByFilter(
230: filters, ProcessInstance.class, _processInstances
231: .values(), countFlag);
232: }
233:
234: public void deleteProcessInstance(String processInstanceId)
235: throws RepositoryException {
236:
237: ProcessInstance procInst = findProcessInstance(processInstanceId);
238: if (procInst == null)
239: throw new ObjectNotFoundException(processInstanceId);
240:
241: // Must cascade delete into attribute instances, activity instances,
242: // work items and attribute instances.
243: for (Iterator iter = procInst.getActivityInstances().iterator(); iter
244: .hasNext();) {
245:
246: ActivityInstance activityInst = (ActivityInstance) iter
247: .next();
248: for (Iterator iter2 = activityInst.getWorkItems()
249: .iterator(); iter2.hasNext();) {
250:
251: WorkItem workItem = (WorkItem) iter2.next();
252: _workItems.remove(workItem.getWorkItemId());
253: }
254: _activityInstances.remove(activityInst
255: .getActivityInstanceId());
256: _activityInstancesByDefnId.remove(new TripleKey(
257: processInstanceId, activityInst
258: .getActivityDefinitionId(), activityInst
259: .getBlockActivityInstanceId()));
260: }
261: _processInstances.remove(processInstanceId);
262: }
263:
264: public AttributeInstance createProcessInstanceAttribute(
265: String processInstanceId, String attributeName,
266: int attributeType, Object attributeValue)
267: throws RepositoryException {
268:
269: BasicProcessInstance procInst = (BasicProcessInstance) findProcessInstance(processInstanceId);
270: AttributeInstance attrInst = new BasicAttributeInstance(
271: procInst, attributeName, attributeType, attributeValue);
272: procInst.addAttributeInstance(attrInst);
273: _attributeInstances.put(new TripleKey(processInstanceId,
274: PROCESS_INSTANCE_TYPE, attributeName), attrInst);
275: return attrInst;
276: }
277:
278: public AttributeInstance findProcessInstanceAttribute(
279: String processInstanceId, String attributeName)
280: throws RepositoryException {
281:
282: ProcessInstance procInst = findProcessInstance(processInstanceId);
283: return procInst.getAttributeInstance(attributeName);
284: }
285:
286: public AttributeInstance[] findProcessInstanceAttributes(
287: String processDefinitionId, String processInstanceId,
288: WMFilter filter, String attrName, boolean countFlag)
289: throws RepositoryException {
290:
291: if (filter == null && processDefinitionId == null
292: && processInstanceId != null && attrName == null) {
293:
294: // This is the only case where we can include system attributes in
295: // the returned list, and the only case where we can obtain the
296: // attributes directly from their owner.
297: Collection attributes = findProcessInstance(
298: processInstanceId).getAttributeInstances().values();
299: AttributeInstance[] attrs = new AttributeInstance[attributes
300: .size()];
301: return countFlag ? attrs : (AttributeInstance[]) attributes
302: .toArray(attrs);
303: } else {
304: return findAttributes(processDefinitionId,
305: processInstanceId, null, processInstanceId,
306: PROCESS_INSTANCE_TYPE, filter, attrName, countFlag);
307: }
308: }
309:
310: private AttributeInstance[] findAttributes(
311: String processDefinitionId, String processInstanceId,
312: String activityDefinitionId, String ownerId,
313: Integer ownerType, WMFilter filter, String attrName,
314: boolean countFlag) throws RepositoryException {
315:
316: int n = 0;
317: if (processDefinitionId != null)
318: n++;
319: if (processInstanceId != null)
320: n++;
321: if (activityDefinitionId != null)
322: n++;
323: if (ownerId != null)
324: n += 2;
325: if (attrName != null)
326: n++;
327: if (filter != null)
328: n++;
329: WMFilter[] filters = new WMFilter[n];
330: n = 0;
331: if (processDefinitionId != null) {
332: filters[n++] = new WMFilter(
333: ActivityInstanceAttributes.PROCESS_DEFINITION_ID,
334: WMFilter.EQ, processDefinitionId);
335: }
336: if (processInstanceId != null) {
337: filters[n++] = new WMFilter(
338: ActivityInstanceAttributes.PROCESS_INSTANCE_ID,
339: WMFilter.EQ, processInstanceId);
340: }
341: if (activityDefinitionId != null) {
342: filters[n++] = new WMFilter(
343: ActivityInstanceAttributes.ACTIVITY_DEFINITION_ID,
344: WMFilter.EQ, activityDefinitionId);
345: }
346: if (ownerId != null) {
347: filters[n++] = new WMFilter(
348: ActivityInstanceAttributes.OWNER_ID, WMFilter.EQ,
349: ownerId);
350: filters[n++] = new WMFilter(
351: ActivityInstanceAttributes.OWNER_TYPE, WMFilter.EQ,
352: ownerType);
353: }
354: if (attrName != null) {
355: filters[n++] = new WMFilter("name", WMFilter.EQ, attrName);
356: }
357: if (filter != null) {
358: filters[n] = filter;
359: }
360: return (AttributeInstance[]) AttributeFilter.findByFilter(
361: filters, BasicAttributeInstance.class,
362: _attributeInstances.values(), countFlag);
363: }
364:
365: public ActivityInstance createActivityInstance(
366: String processDefinitionId, String processInstanceId,
367: String activityDefinitionId, String activityName,
368: JoinInstance join, String blockActivityInstanceId,
369: PersistentIterator blockActivityIterator, int priority,
370: int state, String[] participants)
371: throws RepositoryException {
372:
373: synchronized (_processInstances) {
374: BasicProcessInstance processInstance = (BasicProcessInstance) findProcessInstance(processInstanceId);
375:
376: String activityInstanceId = String
377: .valueOf(_lastActivityInstanceId++);
378:
379: ActivityInstance activityInstance = new BasicActivityInstance(
380: processDefinitionId, processInstance,
381: activityDefinitionId, activityInstanceId, join,
382: blockActivityInstanceId, blockActivityIterator);
383: activityInstance.setName(activityName);
384: activityInstance.setPriority(priority);
385: activityInstance.setState(state);
386: activityInstance.setParticipants(participants);
387:
388: processInstance.addActivityInstance(activityInstance);
389: _activityInstances
390: .put(activityInstanceId, activityInstance);
391: _activityInstancesByDefnId.put(new TripleKey(
392: processInstanceId, activityDefinitionId,
393: blockActivityInstanceId), activityInstance);
394:
395: return activityInstance;
396: }
397: }
398:
399: public ActivityInstance findActivityInstance(
400: String activityInstanceId) throws RepositoryException {
401:
402: ActivityInstance activityInstance = (ActivityInstance) _activityInstances
403: .get(activityInstanceId);
404: if (activityInstance == null)
405: throw new ObjectNotFoundException(activityInstanceId);
406: return activityInstance;
407: }
408:
409: // TODO: this method doesn't work if activityDefinitionId is null.
410: public ActivityInstance findActivityInstance(
411: String processInstanceId, String activityDefinitionId,
412: String blockActivityInstanceId) throws RepositoryException {
413:
414: ActivityInstance activityInstance = (ActivityInstance) _activityInstancesByDefnId
415: .get(new TripleKey(processInstanceId,
416: activityDefinitionId, blockActivityInstanceId));
417: if (activityInstance == null)
418: throw new ObjectNotFoundException(activityDefinitionId);
419: return activityInstance;
420: }
421:
422: public ActivityInstance[] findActivityInstances(
423: String processDefinitionId, String activityDefinitionId,
424: WMFilter filter, boolean countFlag)
425: throws RepositoryException {
426:
427: int n = 0;
428: if (processDefinitionId != null)
429: n++;
430: if (activityDefinitionId != null)
431: n++;
432: if (filter != null)
433: n++;
434: WMFilter[] filters = new WMFilter[n];
435: n = 0;
436: if (processDefinitionId != null) {
437: filters[n++] = new WMFilter(
438: ProcessInstanceAttributes.PROCESS_DEFINITION_ID,
439: WMFilter.EQ, processDefinitionId);
440: }
441: if (activityDefinitionId != null) {
442: filters[n++] = new WMFilter(
443: ActivityInstanceAttributes.ACTIVITY_DEFINITION_ID,
444: WMFilter.EQ, activityDefinitionId);
445: }
446: if (filter != null)
447: filters[n] = filter;
448: return (ActivityInstance[]) AttributeFilter.findByFilter(
449: filters, ActivityInstance.class, _activityInstances
450: .values(), countFlag);
451: }
452:
453: public AttributeInstance createActivityInstanceAttribute(
454: String processInstanceId, String activityInstanceId,
455: String attributeName, int attributeType,
456: Object attributeValue) throws RepositoryException {
457:
458: BasicActivityInstance activity = (BasicActivityInstance) findActivityInstance(activityInstanceId);
459: AttributeInstance attrInst = new BasicAttributeInstance(
460: activity, attributeName, attributeType, attributeValue);
461: activity.addAttributeInstance(attrInst);
462: _attributeInstances.put(new TripleKey(processInstanceId,
463: ACTIVITY_INSTANCE_TYPE, attributeName), attrInst);
464: return attrInst;
465: }
466:
467: public AttributeInstance findActivityInstanceAttribute(
468: String processInstanceId, String activityInstanceId,
469: String attributeName) throws RepositoryException {
470:
471: ActivityInstance activityInstance = findActivityInstance(activityInstanceId);
472: return activityInstance.getAttributeInstance(attributeName);
473: }
474:
475: public AttributeInstance[] findActivityInstanceAttributes(
476: String processDefinitionId, String processInstanceId,
477: String activityDefinitionId, String activityInstanceId,
478: WMFilter filter, String attributeName, boolean countFlag)
479: throws RepositoryException {
480:
481: if (processDefinitionId == null && processInstanceId == null
482: && activityDefinitionId == null
483: && activityInstanceId != null && filter == null
484: && attributeName == null) {
485:
486: ActivityInstance activityInstance = findActivityInstance(activityInstanceId);
487: Collection attributes = activityInstance
488: .getAttributeInstances().values();
489: AttributeInstance[] attrs = new AttributeInstance[attributes
490: .size()];
491: return countFlag ? attrs : (AttributeInstance[]) attributes
492: .toArray(attrs);
493: } else {
494: return findAttributes(processDefinitionId,
495: processInstanceId, activityDefinitionId,
496: activityInstanceId, ACTIVITY_INSTANCE_TYPE, filter,
497: attributeName, countFlag);
498: }
499: }
500:
501: public WorkItem createWorkItem(String processDefinitionId,
502: String processInstanceId, String activityInstanceId,
503: int toolIndex, int state, String performer,
504: String participant) throws RepositoryException {
505:
506: synchronized (_workItems) {
507: BasicActivityInstance activityInstance = (BasicActivityInstance) findActivityInstance(activityInstanceId);
508:
509: String workItemId = String.valueOf(_lastWorkItemId++);
510:
511: WorkItem workItem = new BasicWorkItem(processDefinitionId,
512: processInstanceId, workItemId, activityInstance,
513: toolIndex);
514: workItem.setState(state);
515: workItem.setPerformer(performer);
516: workItem.setParticipant(participant);
517:
518: activityInstance.addWorkItem(workItem);
519: _workItems.put(workItemId, workItem);
520:
521: return workItem;
522: }
523: }
524:
525: public WorkItem findWorkItem(String processInstanceId,
526: String workItemId) throws RepositoryException {
527:
528: WorkItem workItem = (WorkItem) _workItems.get(workItemId);
529: if (workItem == null)
530: throw new ObjectNotFoundException(workItemId);
531: return workItem;
532: }
533:
534: public WorkItem[] findWorkItems(WMFilter filter, boolean countFlag)
535: throws RepositoryException {
536:
537: return (WorkItem[]) AttributeFilter.findByFilter(
538: filter == null ? EMPTY_FILTERS
539: : new WMFilter[] { filter }, WorkItem.class,
540: _workItems.values(), countFlag);
541: }
542:
543: public AttributeInstance createWorkItemAttribute(
544: String processInstanceId, String workItemId,
545: String attributeName, int attributeType,
546: Object attributeValue) throws RepositoryException {
547:
548: BasicWorkItem workItem = (BasicWorkItem) findWorkItem(
549: processInstanceId, workItemId);
550: AttributeInstance attrInst = new BasicAttributeInstance(
551: workItem, attributeName, attributeType, attributeValue);
552: workItem.addAttributeInstance(attrInst);
553: _attributeInstances.put(new TripleKey(processInstanceId,
554: WORKITEM_TYPE, attributeName), attrInst);
555: return attrInst;
556: }
557:
558: public AttributeInstance findWorkItemAttribute(
559: String processInstanceId, String workItemId,
560: String attributeName) throws RepositoryException {
561:
562: return findWorkItem(processInstanceId, workItemId)
563: .getAttributeInstance(attributeName);
564: }
565:
566: public AttributeInstance[] findWorkItemAttributes(
567: String processInstanceId, String workItemId,
568: WMFilter filter, boolean countFlag)
569: throws RepositoryException {
570:
571: if (processInstanceId == null && workItemId != null
572: && filter == null) {
573: Collection attributes = findWorkItem(processInstanceId,
574: workItemId).getAttributeInstances().values();
575: AttributeInstance[] attrs = new AttributeInstance[attributes
576: .size()];
577: return countFlag ? attrs : (AttributeInstance[]) attributes
578: .toArray(attrs);
579: } else {
580: return findAttributes(null, processInstanceId, null,
581: workItemId, WORKITEM_TYPE, filter, null, countFlag);
582: }
583: }
584:
585: public WMAAuditEntry[] findAuditEntries(WMFilter filter)
586: throws RepositoryException {
587:
588: throw new UnsupportedOperationException(
589: "BasicInstanceRepository.listAuditEntries");
590: }
591:
592: public int deleteAuditEntries(WMFilter filter)
593: throws RepositoryException {
594: throw new UnsupportedOperationException(
595: "BasicInstanceRepository.deleteAuditEntries");
596: }
597:
598: protected Log getLogger() {
599: return _logger;
600: }
601:
602: public String getServiceName() {
603: return SERVICE_NAME;
604: }
605: }
|