001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.workflow.spi.ojb;
006:
007: import com.opensymphony.module.propertyset.PropertySet;
008: import com.opensymphony.module.propertyset.PropertySetManager;
009:
010: import com.opensymphony.workflow.QueryNotSupportedException;
011: import com.opensymphony.workflow.StoreException;
012: import com.opensymphony.workflow.query.WorkflowExpressionQuery;
013: import com.opensymphony.workflow.query.WorkflowQuery;
014: import com.opensymphony.workflow.spi.Step;
015: import com.opensymphony.workflow.spi.WorkflowEntry;
016: import com.opensymphony.workflow.spi.WorkflowStore;
017:
018: import org.apache.commons.logging.Log;
019: import org.apache.commons.logging.LogFactory;
020:
021: import org.apache.ojb.broker.PBFactoryException;
022: import org.apache.ojb.broker.PersistenceBroker;
023: import org.apache.ojb.broker.PersistenceBrokerFactory;
024: import org.apache.ojb.broker.query.*;
025:
026: import java.math.BigDecimal;
027:
028: import java.util.*;
029:
030: /**
031: * @author picard
032: * Created on 9 sept. 2003
033: */
034: public class OJBWorkflowStore implements WorkflowStore {
035: //~ Static fields/initializers /////////////////////////////////////////////
036:
037: private static final Log log = LogFactory
038: .getLog(OJBWorkflowStore.class);
039:
040: //~ Constructors ///////////////////////////////////////////////////////////
041:
042: public OJBWorkflowStore() {
043: super ();
044: }
045:
046: //~ Methods ////////////////////////////////////////////////////////////////
047:
048: public void setEntryState(long entryId, int state)
049: throws StoreException {
050: PersistenceBroker broker = null;
051:
052: try {
053: broker = this .getBroker();
054:
055: Criteria criteria = new Criteria();
056: criteria.addEqualTo("id", new Long(entryId));
057:
058: Query query = new QueryByCriteria(OJBWorkflowEntry.class,
059: criteria);
060: OJBWorkflowEntry entry = (OJBWorkflowEntry) broker
061: .getObjectByQuery(query);
062: entry.setState(state);
063: broker.store(entry);
064: } catch (Throwable e) {
065: throw new StoreException("Error to retrieve entry",
066: new Exception(e));
067: } finally {
068: if (broker != null) {
069: broker.close();
070: }
071: }
072: }
073:
074: public PropertySet getPropertySet(long entryId)
075: throws StoreException {
076: HashMap args = new HashMap();
077: args.put("globalKey", "osff_" + entryId);
078:
079: return PropertySetManager.getInstance("ojb", args);
080: }
081:
082: public Step createCurrentStep(long entryId, int stepId,
083: String owner, Date startDate, Date dueDate, String status,
084: long[] previousIds) throws StoreException {
085: PersistenceBroker broker = null;
086: OJBCurrentStep step = new OJBCurrentStep();
087: OJBWorkflowEntry entry;
088:
089: try {
090: broker = this .getBroker();
091:
092: Criteria criteria = new Criteria();
093: criteria.addEqualTo("id", new Long(entryId));
094:
095: Query requete = new QueryByCriteria(OJBWorkflowEntry.class,
096: criteria);
097:
098: entry = (OJBWorkflowEntry) broker.getObjectByQuery(requete);
099:
100: step.setEntry(entry);
101: step.setStepId(stepId);
102: step.setOwner(owner);
103: step.setStartDate(startDate);
104: step.setDueDate(dueDate);
105: step.setStatus(status);
106:
107: List stepIdList = new ArrayList(previousIds.length);
108:
109: for (int i = 0; i < previousIds.length; i++) {
110: long previousId = previousIds[i];
111: stepIdList.add(new Long(previousId));
112: }
113:
114: if (!stepIdList.isEmpty()) {
115: criteria = new Criteria();
116: criteria.addIn("id", stepIdList);
117:
118: requete = new QueryByCriteria(OJBCurrentStep.class,
119: criteria);
120:
121: Collection clPreviousStep = broker
122: .getCollectionByQuery(requete);
123:
124: step.setPreviousSteps(new ArrayList(clPreviousStep));
125: } else {
126: step.setPreviousSteps(Collections.EMPTY_LIST);
127: }
128:
129: if (entry.getCurrentSteps() == null) {
130: ArrayList cSteps = new ArrayList(1);
131: cSteps.add(step);
132: entry.setCurrentSteps(cSteps);
133: } else {
134: entry.getCurrentSteps().add(step);
135: }
136:
137: broker.store(entry);
138: } catch (Exception e) {
139: step = null;
140: throw new StoreException(
141: "Error creating new workflow entry", e);
142: } finally {
143: if (broker != null) {
144: broker.close();
145: }
146: }
147:
148: return step;
149: }
150:
151: public WorkflowEntry createEntry(String workflowName)
152: throws StoreException {
153: PersistenceBroker broker = null;
154:
155: OJBWorkflowEntry entry = new OJBWorkflowEntry();
156: entry.setState(WorkflowEntry.CREATED);
157: entry.setWorkflowName(workflowName);
158:
159: try {
160: broker = this .getBroker();
161:
162: broker.store(entry);
163: } catch (Exception e) {
164: throw new StoreException(
165: "Error creating new workflow entry", e);
166: } finally {
167: if (broker != null) {
168: broker.close();
169: }
170: }
171:
172: return entry;
173: }
174:
175: /* (non-Javadoc)
176: * @see com.opensymphony.workflow.spi.WorkflowStore#findCurrentSteps(long)
177: */
178: public List findCurrentSteps(long entryId) throws StoreException {
179: PersistenceBroker broker = null;
180:
181: Collection clStep = Collections.EMPTY_LIST;
182:
183: try {
184: broker = this .getBroker();
185:
186: Criteria critere = new Criteria();
187: critere.addEqualTo("entry.id", new Long(entryId));
188:
189: Query requete = new QueryByCriteria(OJBCurrentStep.class,
190: critere);
191:
192: clStep = broker.getCollectionByQuery(requete);
193: } catch (Exception e) {
194: throw new StoreException("Error to retrieve current steps",
195: e);
196: } finally {
197: if (broker != null) {
198: broker.close();
199: }
200: }
201:
202: return new ArrayList(clStep);
203: }
204:
205: /* (non-Javadoc)
206: * @see com.opensymphony.workflow.spi.WorkflowStore#findEntry(long)
207: */
208: public WorkflowEntry findEntry(long entryId) throws StoreException {
209: PersistenceBroker broker = null;
210:
211: WorkflowEntry entry = null;
212:
213: try {
214: broker = this .getBroker();
215:
216: Criteria criteria = new Criteria();
217: criteria.addEqualTo("id", new Long(entryId));
218:
219: Query query = new QueryByCriteria(OJBWorkflowEntry.class,
220: criteria);
221:
222: entry = (OJBWorkflowEntry) broker.getObjectByQuery(query);
223: } catch (Throwable e) {
224: throw new StoreException("Error to retrieve entry",
225: new Exception(e));
226: } finally {
227: if (broker != null) {
228: broker.close();
229: }
230: }
231:
232: return entry;
233: }
234:
235: public List findHistorySteps(long entryId) throws StoreException {
236: PersistenceBroker broker = null;
237:
238: Collection clStep = Collections.EMPTY_LIST;
239:
240: try {
241: broker = this .getBroker();
242:
243: Criteria critere = new Criteria();
244: critere.addEqualTo("entry.id", new Long(entryId));
245:
246: Query requete = new QueryByCriteria(OJBHistoryStep.class,
247: critere);
248:
249: clStep = broker.getCollectionByQuery(requete);
250: } catch (Exception e) {
251: throw new StoreException("Error to retrieve history steps",
252: e);
253: } finally {
254: if (broker != null) {
255: broker.close();
256: }
257: }
258:
259: return new ArrayList(clStep);
260: }
261:
262: public void init(Map props) throws StoreException {
263: }
264:
265: public Step markFinished(Step step, int actionId, Date finishDate,
266: String status, String caller) throws StoreException {
267: PersistenceBroker broker = null;
268:
269: OJBCurrentStep currentStep = (OJBCurrentStep) step;
270:
271: try {
272: broker = this .getBroker();
273:
274: currentStep.setActionId(actionId);
275: currentStep.setFinishDate(finishDate);
276: currentStep.setStatus(status);
277: currentStep.setCaller(caller);
278:
279: broker.store(currentStep);
280: } catch (Exception e) {
281: log.error("An exception occured", e);
282:
283: throw new StoreException("Error to store current step", e);
284: } finally {
285: if (broker != null) {
286: broker.close();
287: }
288: }
289:
290: return step;
291: }
292:
293: public void moveToHistory(Step step) throws StoreException {
294: PersistenceBroker broker = null;
295:
296: try {
297: broker = this .getBroker();
298:
299: Criteria criteria = new Criteria();
300: criteria.addEqualTo("id", new Long(step.getEntryId()));
301:
302: Query query = new QueryByCriteria(OJBWorkflowEntry.class,
303: criteria);
304:
305: OJBWorkflowEntry entry = (OJBWorkflowEntry) broker
306: .getObjectByQuery(query);
307:
308: if (entry != null) {
309: OJBHistoryStep hstep = new OJBHistoryStep(
310: (OJBStep) step);
311:
312: entry.getCurrentSteps().remove(step);
313:
314: if (entry.getHistorySteps() == null) {
315: ArrayList hSteps = new ArrayList(1);
316: hSteps.add(hstep);
317: entry.setHistorySteps(hSteps);
318: } else {
319: entry.getHistorySteps().add(hstep);
320: }
321:
322: broker.delete(new OJBCurrentStep((OJBStep) step));
323:
324: broker.store(entry);
325: }
326: } catch (Exception e) {
327: throw new StoreException(
328: "Error to move current step to history", e);
329: } finally {
330: if (broker != null) {
331: broker.close();
332: }
333: }
334: }
335:
336: public List query(WorkflowExpressionQuery query)
337: throws StoreException {
338: throw new QueryNotSupportedException(
339: "OJB Store does not support WorkflowExpressionQuery");
340: }
341:
342: public List query(WorkflowQuery query) throws StoreException {
343: PersistenceBroker broker = null;
344:
345: List results = new ArrayList();
346:
347: try {
348: broker = this .getBroker();
349:
350: int qtype = query.getType();
351:
352: if (qtype == 0) { // then not set, so look in sub queries
353: // todo: not sure if you would have a query that would look in both old and new, if so, i'll have to change this - TR
354: // but then again, why are there redundant tables in the first place? the data model should probably change
355:
356: if (query.getLeft() != null) {
357: qtype = query.getLeft().getType();
358: }
359: }
360:
361: String sel = queryWhere(query);
362:
363: if (log.isDebugEnabled()) {
364: log.debug(sel);
365: }
366:
367: Criteria critere = new Criteria();
368: critere.addSql(sel);
369:
370: ReportQueryByCriteria report;
371:
372: if (qtype == WorkflowQuery.CURRENT) {
373: report = new ReportQueryByCriteria(
374: OJBCurrentStep.class, critere, true); // true = Select distinct
375: } else {
376: report = new ReportQueryByCriteria(
377: OJBHistoryStep.class, critere, true); // true = Select distinct
378: }
379:
380: report.setColumns(new String[] { "entryId" });
381:
382: Iterator iter = broker
383: .getReportQueryIteratorByQuery(report);
384:
385: while (iter.hasNext()) {
386: Object[] obj = (Object[]) iter.next();
387: BigDecimal entryId = (BigDecimal) obj[0];
388:
389: results.add(new Long(entryId.longValue()));
390: }
391: } catch (Exception e) {
392: throw new StoreException("SQL Exception in query: "
393: + e.getMessage());
394: } finally {
395: if (broker != null) {
396: broker.close();
397: }
398: }
399:
400: return results;
401: }
402:
403: private PersistenceBroker getBroker() throws PBFactoryException {
404: PersistenceBroker broker = PersistenceBrokerFactory
405: .defaultPersistenceBroker();
406:
407: return broker;
408: }
409:
410: private static String escape(String s) {
411: StringBuffer sb = new StringBuffer(s);
412:
413: char c;
414: char[] chars = s.toCharArray();
415:
416: for (int i = 0; i < chars.length; i++) {
417: c = chars[i];
418:
419: switch (c) {
420: case '\'':
421: sb.insert(i, '\'');
422: i++;
423:
424: break;
425:
426: case '\\':
427: sb.insert(i, '\\');
428: i++;
429: }
430: }
431:
432: return sb.toString();
433: }
434:
435: private String queryComparison(WorkflowQuery query) {
436: Object value = query.getValue();
437: int operator = query.getOperator();
438: int field = query.getField();
439:
440: //int type = query.getType();
441: String oper;
442:
443: switch (operator) {
444: case WorkflowQuery.EQUALS:
445: oper = " = ";
446:
447: break;
448:
449: case WorkflowQuery.NOT_EQUALS:
450: oper = " <> ";
451:
452: break;
453:
454: case WorkflowQuery.GT:
455: oper = " > ";
456:
457: break;
458:
459: case WorkflowQuery.LT:
460: oper = " < ";
461:
462: break;
463:
464: default:
465: oper = " = ";
466: }
467:
468: String left;
469: String right;
470:
471: switch (field) {
472: case WorkflowQuery.ACTION: // actionId
473: left = "ACTION_ID";
474:
475: break;
476:
477: case WorkflowQuery.CALLER:
478: left = "CALLER";
479:
480: break;
481:
482: case WorkflowQuery.FINISH_DATE:
483: left = "FINISH_DATE";
484:
485: break;
486:
487: case WorkflowQuery.OWNER:
488: left = "OWNER";
489:
490: break;
491:
492: case WorkflowQuery.START_DATE:
493: left = "START_DATE";
494:
495: break;
496:
497: case WorkflowQuery.STEP: // stepId
498: left = "STEP_ID";
499:
500: break;
501:
502: case WorkflowQuery.STATUS:
503: left = "STATUS";
504:
505: break;
506:
507: default:
508: left = "1";
509: }
510:
511: if (value != null) {
512: right = "'" + escape(value.toString()) + "'";
513: } else {
514: right = "null";
515: }
516:
517: return left + oper + right;
518: }
519:
520: private String queryWhere(WorkflowQuery query) {
521: if (query.getLeft() == null) {
522: // leaf node
523: return queryComparison(query);
524: } else {
525: int operator = query.getOperator();
526: WorkflowQuery left = query.getLeft();
527: WorkflowQuery right = query.getRight();
528:
529: switch (operator) {
530: case WorkflowQuery.AND:
531: return "(" + queryWhere(left) + " AND "
532: + queryWhere(right) + ")";
533:
534: case WorkflowQuery.OR:
535: return "(" + queryWhere(left) + " OR "
536: + queryWhere(right) + ")";
537:
538: case WorkflowQuery.XOR:
539: return "(" + queryWhere(left) + " XOR "
540: + queryWhere(right) + ")";
541: }
542: }
543:
544: return ""; // not sure if we should throw an exception or how this should be handled
545: }
546: }
|