001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: /*
006: * Created on Feb 12, 2004
007: *
008: *
009: */
010: package com.opensymphony.workflow.spi.prevayler;
011:
012: import com.opensymphony.util.DataUtil;
013: import com.opensymphony.util.TextUtils;
014:
015: import com.opensymphony.workflow.StoreException;
016: import com.opensymphony.workflow.query.Expression;
017: import com.opensymphony.workflow.query.FieldExpression;
018: import com.opensymphony.workflow.query.NestedExpression;
019: import com.opensymphony.workflow.query.WorkflowExpressionQuery;
020: import com.opensymphony.workflow.query.WorkflowQuery;
021: import com.opensymphony.workflow.spi.SimpleStep;
022: import com.opensymphony.workflow.spi.SimpleWorkflowEntry;
023: import com.opensymphony.workflow.spi.WorkflowStore;
024:
025: import java.security.InvalidParameterException;
026:
027: import java.util.Date;
028: import java.util.Iterator;
029: import java.util.List;
030:
031: /**
032: *
033: * This is basically the query logic cut and pasted from MemoryWorkflowStore. I've separated
034: * it into a separate class which relies on WorkflowStore for its query base, that way any future
035: * or other WorkflowStore can rely on this logic.
036: *
037: * I thought about refactoring MemoryWorkflowStore to use this class, but as its such a well used
038: * class I didn't want to do it before some more eyes looked at things here.
039: *
040: * @author Christopher Farnham
041: **/
042: public class QueryLogic {
043: //~ Instance fields ////////////////////////////////////////////////////////
044:
045: private WorkflowStore _store = null;
046:
047: //~ Constructors ///////////////////////////////////////////////////////////
048:
049: public QueryLogic(WorkflowStore store) {
050: _store = store;
051: }
052:
053: private QueryLogic() {
054: super ();
055: }
056:
057: //~ Methods ////////////////////////////////////////////////////////////////
058:
059: public boolean query(Long entryId, WorkflowExpressionQuery query)
060: throws StoreException {
061: Expression expression = query.getExpression();
062:
063: if (expression.isNested()) {
064: return this .checkNestedExpression(entryId.longValue(),
065: (NestedExpression) expression);
066: } else {
067: return this .checkExpression(entryId.longValue(),
068: (FieldExpression) expression);
069: }
070: }
071:
072: public boolean query(Long entryId, WorkflowQuery query)
073: throws StoreException {
074: if (query.getLeft() == null) {
075: return queryBasic(entryId, query);
076: } else {
077: int operator = query.getOperator();
078: WorkflowQuery left = query.getLeft();
079: WorkflowQuery right = query.getRight();
080:
081: switch (operator) {
082: case WorkflowQuery.AND:
083: return query(entryId, left) && query(entryId, right);
084:
085: case WorkflowQuery.OR:
086: return query(entryId, left) || query(entryId, right);
087:
088: case WorkflowQuery.XOR:
089: return query(entryId, left) ^ query(entryId, right);
090: }
091: }
092:
093: return false;
094: }
095:
096: private boolean checkExpression(long entryId,
097: FieldExpression expression) throws StoreException {
098: Object value = expression.getValue();
099: int operator = expression.getOperator();
100: int field = expression.getField();
101: int context = expression.getContext();
102:
103: Long id = new Long(entryId);
104:
105: if (context == FieldExpression.ENTRY) {
106: SimpleWorkflowEntry theEntry = (SimpleWorkflowEntry) _store
107: .findEntry(entryId);
108:
109: if (field == FieldExpression.NAME) {
110: return this .compareText(theEntry.getWorkflowName(),
111: (String) value, operator);
112: }
113:
114: if (field == FieldExpression.STATE) {
115: return this .compareLong(DataUtil
116: .getInt((Integer) value), theEntry.getState(),
117: operator);
118: }
119:
120: throw new InvalidParameterException("unknown field");
121: }
122:
123: List steps;
124:
125: if (context == FieldExpression.CURRENT_STEPS) {
126: //steps = (List) currentStepsCache.get(id);
127: steps = (List) _store.findCurrentSteps(id.longValue());
128: } else if (context == FieldExpression.HISTORY_STEPS) {
129: //steps = (List) historyStepsCache.get(id);
130: steps = (List) _store.findHistorySteps(id.longValue());
131: } else {
132: throw new InvalidParameterException("unknown field context");
133: }
134:
135: if (steps == null) {
136: return false;
137: }
138:
139: boolean expressionResult = false;
140:
141: switch (field) {
142: case FieldExpression.ACTION:
143:
144: long actionId = DataUtil.getInt((Integer) value);
145:
146: for (Iterator iterator = steps.iterator(); iterator
147: .hasNext();) {
148: SimpleStep step = (SimpleStep) iterator.next();
149:
150: if (this .compareLong(step.getActionId(), actionId,
151: operator)) {
152: expressionResult = true;
153:
154: break;
155: }
156: }
157:
158: break;
159:
160: case FieldExpression.CALLER:
161:
162: String caller = (String) value;
163:
164: for (Iterator iterator = steps.iterator(); iterator
165: .hasNext();) {
166: SimpleStep step = (SimpleStep) iterator.next();
167:
168: if (this
169: .compareText(step.getCaller(), caller, operator)) {
170: expressionResult = true;
171:
172: break;
173: }
174: }
175:
176: break;
177:
178: case FieldExpression.FINISH_DATE:
179:
180: Date finishDate = (Date) value;
181:
182: for (Iterator iterator = steps.iterator(); iterator
183: .hasNext();) {
184: SimpleStep step = (SimpleStep) iterator.next();
185:
186: if (this .compareDate(step.getFinishDate(), finishDate,
187: operator)) {
188: expressionResult = true;
189:
190: break;
191: }
192: }
193:
194: break;
195:
196: case FieldExpression.OWNER:
197:
198: String owner = (String) value;
199:
200: for (Iterator iterator = steps.iterator(); iterator
201: .hasNext();) {
202: SimpleStep step = (SimpleStep) iterator.next();
203:
204: if (this .compareText(step.getOwner(), owner, operator)) {
205: expressionResult = true;
206:
207: break;
208: }
209: }
210:
211: break;
212:
213: case FieldExpression.START_DATE:
214:
215: Date startDate = (Date) value;
216:
217: for (Iterator iterator = steps.iterator(); iterator
218: .hasNext();) {
219: SimpleStep step = (SimpleStep) iterator.next();
220:
221: if (this .compareDate(step.getStartDate(), startDate,
222: operator)) {
223: expressionResult = true;
224:
225: break;
226: }
227: }
228:
229: break;
230:
231: case FieldExpression.STEP:
232:
233: int stepId = DataUtil.getInt((Integer) value);
234:
235: for (Iterator iterator = steps.iterator(); iterator
236: .hasNext();) {
237: SimpleStep step = (SimpleStep) iterator.next();
238:
239: if (this
240: .compareLong(step.getStepId(), stepId, operator)) {
241: expressionResult = true;
242:
243: break;
244: }
245: }
246:
247: break;
248:
249: case FieldExpression.STATUS:
250:
251: String status = (String) value;
252:
253: for (Iterator iterator = steps.iterator(); iterator
254: .hasNext();) {
255: SimpleStep step = (SimpleStep) iterator.next();
256:
257: if (this
258: .compareText(step.getStatus(), status, operator)) {
259: expressionResult = true;
260:
261: break;
262: }
263: }
264:
265: break;
266:
267: case FieldExpression.DUE_DATE:
268:
269: Date dueDate = (Date) value;
270:
271: for (Iterator iterator = steps.iterator(); iterator
272: .hasNext();) {
273: SimpleStep step = (SimpleStep) iterator.next();
274:
275: if (this .compareDate(step.getDueDate(), dueDate,
276: operator)) {
277: expressionResult = true;
278:
279: break;
280: }
281: }
282:
283: break;
284: }
285:
286: if (expression.isNegate()) {
287: return !expressionResult;
288: } else {
289: return expressionResult;
290: }
291: }
292:
293: private boolean checkNestedExpression(long entryId,
294: NestedExpression nestedExpression) throws StoreException {
295: for (int i = 0; i < nestedExpression.getExpressionCount(); i++) {
296: boolean expressionResult;
297: Expression expression = nestedExpression.getExpression(i);
298:
299: if (expression.isNested()) {
300: expressionResult = this .checkNestedExpression(entryId,
301: (NestedExpression) expression);
302: } else {
303: expressionResult = this .checkExpression(entryId,
304: (FieldExpression) expression);
305: }
306:
307: if (nestedExpression.getExpressionOperator() == NestedExpression.AND) {
308: if (expressionResult == false) {
309: return nestedExpression.isNegate();
310: }
311: } else if (nestedExpression.getExpressionOperator() == NestedExpression.OR) {
312: if (expressionResult == true) {
313: return !nestedExpression.isNegate();
314: }
315: }
316: }
317:
318: if (nestedExpression.getExpressionOperator() == NestedExpression.AND) {
319: return !nestedExpression.isNegate();
320: } else if (nestedExpression.getExpressionOperator() == NestedExpression.OR) {
321: return nestedExpression.isNegate();
322: }
323:
324: throw new InvalidParameterException("unknown operator");
325: }
326:
327: private boolean compareDate(Date value1, Date value2, int operator) {
328: switch (operator) {
329: case FieldExpression.EQUALS:
330: return value1.compareTo(value2) == 0;
331:
332: case FieldExpression.NOT_EQUALS:
333: return value1.compareTo(value2) != 0;
334:
335: case FieldExpression.GT:
336: return (value1.compareTo(value2) > 0);
337:
338: case FieldExpression.LT:
339: return value1.compareTo(value2) < 0;
340: }
341:
342: throw new InvalidParameterException("unknown field operator");
343: }
344:
345: private boolean compareLong(long value1, long value2, int operator) {
346: switch (operator) {
347: case FieldExpression.EQUALS:
348: return value1 == value2;
349:
350: case FieldExpression.NOT_EQUALS:
351: return value1 != value2;
352:
353: case FieldExpression.GT:
354: return value1 > value2;
355:
356: case FieldExpression.LT:
357: return value1 < value2;
358: }
359:
360: throw new InvalidParameterException("unknown field operator");
361: }
362:
363: private boolean compareText(String value1, String value2,
364: int operator) {
365: switch (operator) {
366: case FieldExpression.EQUALS:
367: return TextUtils.noNull(value1).equals(value2);
368:
369: case FieldExpression.NOT_EQUALS:
370: return !TextUtils.noNull(value1).equals(value2);
371:
372: case FieldExpression.GT:
373: return TextUtils.noNull(value1).compareTo(value2) > 0;
374:
375: case FieldExpression.LT:
376: return TextUtils.noNull(value1).compareTo(value2) < 0;
377: }
378:
379: throw new InvalidParameterException("unknown field operator");
380: }
381:
382: private boolean queryBasic(Long entryId, WorkflowQuery query)
383: throws StoreException {
384: // the query object is a comparison
385: Object value = query.getValue();
386: int operator = query.getOperator();
387: int field = query.getField();
388: int type = query.getType();
389:
390: switch (operator) {
391: case WorkflowQuery.EQUALS:
392: return queryEquals(entryId, field, type, value);
393:
394: case WorkflowQuery.NOT_EQUALS:
395: return queryNotEquals(entryId, field, type, value);
396:
397: case WorkflowQuery.GT:
398: return queryGreaterThan(entryId, field, type, value);
399:
400: case WorkflowQuery.LT:
401: return queryLessThan(entryId, field, type, value);
402: }
403:
404: return false;
405: }
406:
407: private boolean queryEquals(Long entryId, int field, int type,
408: Object value) throws StoreException {
409: List steps;
410:
411: if (type == WorkflowQuery.CURRENT) {
412: //steps = (List) currentStepsCache.get(entryId);
413: steps = (List) _store.findCurrentSteps(entryId.longValue());
414: } else {
415: //steps = (List) historyStepsCache.get(entryId);
416: steps = (List) _store.findCurrentSteps(entryId.longValue());
417: }
418:
419: switch (field) {
420: case WorkflowQuery.ACTION:
421:
422: long actionId = DataUtil.getInt((Integer) value);
423:
424: for (Iterator iterator = steps.iterator(); iterator
425: .hasNext();) {
426: SimpleStep step = (SimpleStep) iterator.next();
427:
428: if (step.getActionId() == actionId) {
429: return true;
430: }
431: }
432:
433: return false;
434:
435: case WorkflowQuery.CALLER:
436:
437: String caller = (String) value;
438:
439: for (Iterator iterator = steps.iterator(); iterator
440: .hasNext();) {
441: SimpleStep step = (SimpleStep) iterator.next();
442:
443: if (TextUtils.noNull(step.getCaller()).equals(caller)) {
444: return true;
445: }
446: }
447:
448: return false;
449:
450: case WorkflowQuery.FINISH_DATE:
451:
452: Date finishDate = (Date) value;
453:
454: for (Iterator iterator = steps.iterator(); iterator
455: .hasNext();) {
456: SimpleStep step = (SimpleStep) iterator.next();
457:
458: if (finishDate.equals(step.getFinishDate())) {
459: return true;
460: }
461: }
462:
463: return false;
464:
465: case WorkflowQuery.OWNER:
466:
467: String owner = (String) value;
468:
469: for (Iterator iterator = steps.iterator(); iterator
470: .hasNext();) {
471: SimpleStep step = (SimpleStep) iterator.next();
472:
473: if (TextUtils.noNull(step.getOwner()).equals(owner)) {
474: return true;
475: }
476: }
477:
478: return false;
479:
480: case WorkflowQuery.START_DATE:
481:
482: Date startDate = (Date) value;
483:
484: for (Iterator iterator = steps.iterator(); iterator
485: .hasNext();) {
486: SimpleStep step = (SimpleStep) iterator.next();
487:
488: if (startDate.equals(step.getStartDate())) {
489: return true;
490: }
491: }
492:
493: return false;
494:
495: case WorkflowQuery.STEP:
496:
497: int stepId = DataUtil.getInt((Integer) value);
498:
499: for (Iterator iterator = steps.iterator(); iterator
500: .hasNext();) {
501: SimpleStep step = (SimpleStep) iterator.next();
502:
503: if (stepId == step.getStepId()) {
504: return true;
505: }
506: }
507:
508: return false;
509:
510: case WorkflowQuery.STATUS:
511:
512: String status = (String) value;
513:
514: for (Iterator iterator = steps.iterator(); iterator
515: .hasNext();) {
516: SimpleStep step = (SimpleStep) iterator.next();
517:
518: if (TextUtils.noNull(step.getStatus()).equals(status)) {
519: return true;
520: }
521: }
522:
523: return false;
524: }
525:
526: return false;
527: }
528:
529: private boolean queryGreaterThan(Long entryId, int field, int type,
530: Object value) throws StoreException {
531: List steps;
532:
533: if (type == WorkflowQuery.CURRENT) {
534: //steps = (List) currentStepsCache.get(entryId);
535: steps = (List) _store.findCurrentSteps(entryId.longValue());
536: } else {
537: //steps = (List) historyStepsCache.get(entryId);
538: steps = (List) _store.findHistorySteps(entryId.longValue());
539: }
540:
541: switch (field) {
542: case WorkflowQuery.ACTION:
543:
544: long actionId = DataUtil.getLong((Long) value);
545:
546: for (Iterator iterator = steps.iterator(); iterator
547: .hasNext();) {
548: SimpleStep step = (SimpleStep) iterator.next();
549:
550: if (step.getActionId() > actionId) {
551: return true;
552: }
553: }
554:
555: return false;
556:
557: case WorkflowQuery.CALLER:
558:
559: String caller = (String) value;
560:
561: for (Iterator iterator = steps.iterator(); iterator
562: .hasNext();) {
563: SimpleStep step = (SimpleStep) iterator.next();
564:
565: if (TextUtils.noNull(step.getCaller())
566: .compareTo(caller) > 0) {
567: return true;
568: }
569: }
570:
571: return false;
572:
573: case WorkflowQuery.FINISH_DATE:
574:
575: Date finishDate = (Date) value;
576:
577: for (Iterator iterator = steps.iterator(); iterator
578: .hasNext();) {
579: SimpleStep step = (SimpleStep) iterator.next();
580:
581: if (step.getFinishDate().compareTo(finishDate) > 0) {
582: return true;
583: }
584: }
585:
586: return false;
587:
588: case WorkflowQuery.OWNER:
589:
590: String owner = (String) value;
591:
592: for (Iterator iterator = steps.iterator(); iterator
593: .hasNext();) {
594: SimpleStep step = (SimpleStep) iterator.next();
595:
596: if (TextUtils.noNull(step.getOwner()).compareTo(owner) > 0) {
597: return true;
598: }
599: }
600:
601: return false;
602:
603: case WorkflowQuery.START_DATE:
604:
605: Date startDate = (Date) value;
606:
607: for (Iterator iterator = steps.iterator(); iterator
608: .hasNext();) {
609: SimpleStep step = (SimpleStep) iterator.next();
610:
611: if (step.getStartDate().compareTo(startDate) > 0) {
612: return true;
613: }
614: }
615:
616: return false;
617:
618: case WorkflowQuery.STEP:
619:
620: int stepId = DataUtil.getInt((Integer) value);
621:
622: for (Iterator iterator = steps.iterator(); iterator
623: .hasNext();) {
624: SimpleStep step = (SimpleStep) iterator.next();
625:
626: if (step.getStepId() > stepId) {
627: return true;
628: }
629: }
630:
631: return false;
632:
633: case WorkflowQuery.STATUS:
634:
635: String status = (String) value;
636:
637: for (Iterator iterator = steps.iterator(); iterator
638: .hasNext();) {
639: SimpleStep step = (SimpleStep) iterator.next();
640:
641: if (TextUtils.noNull(step.getStatus())
642: .compareTo(status) > 0) {
643: return true;
644: }
645: }
646:
647: return false;
648: }
649:
650: return false;
651: }
652:
653: private boolean queryLessThan(Long entryId, int field, int type,
654: Object value) throws StoreException {
655: List steps;
656:
657: if (type == WorkflowQuery.CURRENT) {
658: //steps = (List) currentStepsCache.get(entryId);
659: steps = (List) _store.findCurrentSteps(entryId.longValue());
660: } else {
661: //steps = (List) historyStepsCache.get(entryId);
662: steps = (List) _store.findHistorySteps(entryId.longValue());
663: }
664:
665: switch (field) {
666: case WorkflowQuery.ACTION:
667:
668: long actionId = DataUtil.getLong((Long) value);
669:
670: for (Iterator iterator = steps.iterator(); iterator
671: .hasNext();) {
672: SimpleStep step = (SimpleStep) iterator.next();
673:
674: if (step.getActionId() < actionId) {
675: return true;
676: }
677: }
678:
679: return false;
680:
681: case WorkflowQuery.CALLER:
682:
683: String caller = (String) value;
684:
685: for (Iterator iterator = steps.iterator(); iterator
686: .hasNext();) {
687: SimpleStep step = (SimpleStep) iterator.next();
688:
689: if (TextUtils.noNull(step.getCaller())
690: .compareTo(caller) < 0) {
691: return true;
692: }
693: }
694:
695: return false;
696:
697: case WorkflowQuery.FINISH_DATE:
698:
699: Date finishDate = (Date) value;
700:
701: for (Iterator iterator = steps.iterator(); iterator
702: .hasNext();) {
703: SimpleStep step = (SimpleStep) iterator.next();
704:
705: if (step.getFinishDate().compareTo(finishDate) < 0) {
706: return true;
707: }
708: }
709:
710: return false;
711:
712: case WorkflowQuery.OWNER:
713:
714: String owner = (String) value;
715:
716: for (Iterator iterator = steps.iterator(); iterator
717: .hasNext();) {
718: SimpleStep step = (SimpleStep) iterator.next();
719:
720: if (TextUtils.noNull(step.getOwner()).compareTo(owner) < 0) {
721: return true;
722: }
723: }
724:
725: return false;
726:
727: case WorkflowQuery.START_DATE:
728:
729: Date startDate = (Date) value;
730:
731: for (Iterator iterator = steps.iterator(); iterator
732: .hasNext();) {
733: SimpleStep step = (SimpleStep) iterator.next();
734:
735: if (step.getStartDate().compareTo(startDate) < 0) {
736: return true;
737: }
738: }
739:
740: return false;
741:
742: case WorkflowQuery.STEP:
743:
744: int stepId = DataUtil.getInt((Integer) value);
745:
746: for (Iterator iterator = steps.iterator(); iterator
747: .hasNext();) {
748: SimpleStep step = (SimpleStep) iterator.next();
749:
750: if (step.getStepId() < stepId) {
751: return true;
752: }
753: }
754:
755: return false;
756:
757: case WorkflowQuery.STATUS:
758:
759: String status = (String) value;
760:
761: for (Iterator iterator = steps.iterator(); iterator
762: .hasNext();) {
763: SimpleStep step = (SimpleStep) iterator.next();
764:
765: if (TextUtils.noNull(step.getStatus())
766: .compareTo(status) < 0) {
767: return true;
768: }
769: }
770:
771: return false;
772: }
773:
774: return false;
775: }
776:
777: private boolean queryNotEquals(Long entryId, int field, int type,
778: Object value) throws StoreException {
779: List steps;
780:
781: if (type == WorkflowQuery.CURRENT) {
782: //steps = (List) currentStepsCache.get(entryId);
783: steps = (List) _store.findCurrentSteps(entryId.longValue());
784: } else {
785: //steps = (List) historyStepsCache.get(entryId);
786: steps = (List) _store.findHistorySteps(entryId.longValue());
787: }
788:
789: switch (field) {
790: case WorkflowQuery.ACTION:
791:
792: long actionId = DataUtil.getLong((Long) value);
793:
794: for (Iterator iterator = steps.iterator(); iterator
795: .hasNext();) {
796: SimpleStep step = (SimpleStep) iterator.next();
797:
798: if (step.getActionId() != actionId) {
799: return true;
800: }
801: }
802:
803: return false;
804:
805: case WorkflowQuery.CALLER:
806:
807: String caller = (String) value;
808:
809: for (Iterator iterator = steps.iterator(); iterator
810: .hasNext();) {
811: SimpleStep step = (SimpleStep) iterator.next();
812:
813: if (!TextUtils.noNull(step.getCaller()).equals(caller)) {
814: return true;
815: }
816: }
817:
818: return false;
819:
820: case WorkflowQuery.FINISH_DATE:
821:
822: Date finishDate = (Date) value;
823:
824: for (Iterator iterator = steps.iterator(); iterator
825: .hasNext();) {
826: SimpleStep step = (SimpleStep) iterator.next();
827:
828: if (!finishDate.equals(step.getFinishDate())) {
829: return true;
830: }
831: }
832:
833: return false;
834:
835: case WorkflowQuery.OWNER:
836:
837: String owner = (String) value;
838:
839: for (Iterator iterator = steps.iterator(); iterator
840: .hasNext();) {
841: SimpleStep step = (SimpleStep) iterator.next();
842:
843: if (!TextUtils.noNull(step.getOwner()).equals(owner)) {
844: return true;
845: }
846: }
847:
848: return false;
849:
850: case WorkflowQuery.START_DATE:
851:
852: Date startDate = (Date) value;
853:
854: for (Iterator iterator = steps.iterator(); iterator
855: .hasNext();) {
856: SimpleStep step = (SimpleStep) iterator.next();
857:
858: if (!startDate.equals(step.getStartDate())) {
859: return true;
860: }
861: }
862:
863: return false;
864:
865: case WorkflowQuery.STEP:
866:
867: int stepId = DataUtil.getInt((Integer) value);
868:
869: for (Iterator iterator = steps.iterator(); iterator
870: .hasNext();) {
871: SimpleStep step = (SimpleStep) iterator.next();
872:
873: if (stepId != step.getStepId()) {
874: return true;
875: }
876: }
877:
878: return false;
879:
880: case WorkflowQuery.STATUS:
881:
882: String status = (String) value;
883:
884: for (Iterator iterator = steps.iterator(); iterator
885: .hasNext();) {
886: SimpleStep step = (SimpleStep) iterator.next();
887:
888: if (!TextUtils.noNull(step.getStatus()).equals(status)) {
889: return true;
890: }
891: }
892:
893: return false;
894: }
895:
896: return false;
897: }
898: }
|