KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > workflow > spi > jdbc > JDBCWorkflowStore


1 /*
2  * Copyright (c) 2002-2003 by OpenSymphony
3  * All rights reserved.
4  */

5 package com.opensymphony.workflow.spi.jdbc;
6
7 import com.opensymphony.module.propertyset.PropertySet;
8 import com.opensymphony.module.propertyset.PropertySetManager;
9
10 import com.opensymphony.workflow.StoreException;
11 import com.opensymphony.workflow.query.Expression;
12 import com.opensymphony.workflow.query.FieldExpression;
13 import com.opensymphony.workflow.query.NestedExpression;
14 import com.opensymphony.workflow.query.WorkflowExpressionQuery;
15 import com.opensymphony.workflow.query.WorkflowQuery;
16 import com.opensymphony.workflow.spi.SimpleStep;
17 import com.opensymphony.workflow.spi.SimpleWorkflowEntry;
18 import com.opensymphony.workflow.spi.Step;
19 import com.opensymphony.workflow.spi.WorkflowEntry;
20 import com.opensymphony.workflow.spi.WorkflowStore;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 import java.sql.*;
26
27 import java.util.*;
28 import java.util.Date JavaDoc;
29
30 import javax.naming.InitialContext JavaDoc;
31 import javax.naming.NamingException JavaDoc;
32
33 import javax.sql.DataSource JavaDoc;
34
35
36 /**
37  * JDBC implementation.
38  * <p>
39  *
40  * The following properties are all <b>required</b>:
41  * <ul>
42  * <li><b>datasource</b> - the JNDI location for the DataSource that is to be used.</li>
43  * <li><b>entry.sequence</b> - SQL query that returns the next ID for a workflow entry</li>
44  * <li><b>entry.table</b> - table name for workflow entry</li>
45  * <li><b>entry.id</b> - column name for workflow entry ID field</li>
46  * <li><b>entry.name</b> - column name for workflow entry name field</li>
47  * <li><b>entry.state</b> - column name for workflow entry state field</li>
48  * <li><b>step.sequence</b> - SQL query that returns the next ID for a workflow step</li>
49  * <li><b>history.table</b> - table name for steps in history</li>
50  * <li><b>current.table</b> - table name for current steps</li>
51  * <li><b>step.id</b> - column name for step ID field</li>
52  * <li><b>step.entryId</b> - column name for workflow entry ID field (foreign key relationship to [entry.table].[entry.id])</li>
53  * <li><b>step.stepId</b> - column name for step workflow definition step field</li>
54  * <li><b>step.actionId</b> - column name for step action field</li>
55  * <li><b>step.owner</b> - column name for step owner field</li>
56  * <li><b>step.caller</b> - column name for step caller field</li>
57  * <li><b>step.startDate</b> - column name for step start date field</li>
58  * <li><b>step.dueDate</b> - column name for optional step due date field</li>
59  * <li><b>step.finishDate</b> - column name for step finish date field</li>
60  * <li><b>step.status</b> - column name for step status field</li>
61  * <li><b>currentPrev.table</b> - table name for the previous IDs for current steps</li>
62  * <li><b>historyPrev.table</b> - table name for the previous IDs for history steps</li>
63  * <li><b>step.previousId</b> - column name for step ID field (foreign key relation to [history.table].[step.id] or [current.table].[step.id])</li>
64  * </ul>
65  *
66  * @author <a HREF="mailto:plightbo@hotmail.com">Pat Lightbody</a>
67  */

68 public class JDBCWorkflowStore implements WorkflowStore {
69     //~ Static fields/initializers /////////////////////////////////////////////
70

71     private static final Log log = LogFactory.getLog(JDBCWorkflowStore.class);
72
73     //~ Instance fields ////////////////////////////////////////////////////////
74

75     protected DataSource JavaDoc ds;
76     protected String JavaDoc currentPrevTable;
77     protected String JavaDoc currentTable;
78     protected String JavaDoc entryId;
79     protected String JavaDoc entryName;
80     protected String JavaDoc entrySequence;
81     protected String JavaDoc entryState;
82     protected String JavaDoc entryTable;
83     protected String JavaDoc historyPrevTable;
84     protected String JavaDoc historyTable;
85     protected String JavaDoc stepActionId;
86     protected String JavaDoc stepCaller;
87     protected String JavaDoc stepDueDate;
88     protected String JavaDoc stepEntryId;
89     protected String JavaDoc stepFinishDate;
90     protected String JavaDoc stepId;
91     protected String JavaDoc stepOwner;
92     protected String JavaDoc stepPreviousId;
93     protected String JavaDoc stepSequence;
94     protected String JavaDoc stepStartDate;
95     protected String JavaDoc stepStatus;
96     protected String JavaDoc stepStepId;
97     protected boolean closeConnWhenDone = false;
98
99     //~ Methods ////////////////////////////////////////////////////////////////
100

101     public void setEntryState(long id, int state) throws StoreException {
102         Connection conn = null;
103         PreparedStatement ps = null;
104
105         try {
106             conn = getConnection();
107
108             String JavaDoc sql = "UPDATE " + entryTable + " SET " + entryState + " = ? WHERE " + entryId + " = ?";
109             ps = conn.prepareStatement(sql);
110             ps.setInt(1, state);
111             ps.setLong(2, id);
112             ps.executeUpdate();
113         } catch (SQLException e) {
114             throw new StoreException("Unable to update state for workflow instance #" + id + " to " + state, e);
115         } finally {
116             cleanup(conn, ps, null);
117         }
118     }
119
120     public PropertySet getPropertySet(long entryId) {
121         HashMap args = new HashMap(1);
122         args.put("globalKey", "osff_" + entryId);
123
124         return PropertySetManager.getInstance("jdbc", args);
125     }
126
127     public Step createCurrentStep(long entryId, int wfStepId, String JavaDoc owner, Date JavaDoc startDate, Date JavaDoc dueDate, String JavaDoc status, long[] previousIds) throws StoreException {
128         Connection conn = null;
129
130         try {
131             conn = getConnection();
132
133             long id = createCurrentStep(conn, entryId, wfStepId, owner, startDate, dueDate, status);
134             addPreviousSteps(conn, id, previousIds);
135
136             return new SimpleStep(id, entryId, wfStepId, 0, owner, startDate, dueDate, null, status, previousIds, null);
137         } catch (SQLException e) {
138             throw new StoreException("Unable to create current step for workflow instance #" + entryId, e);
139         } finally {
140             cleanup(conn, null, null);
141         }
142     }
143
144     public WorkflowEntry createEntry(String JavaDoc workflowName) throws StoreException {
145         Connection conn = null;
146         PreparedStatement stmt = null;
147
148         try {
149             conn = getConnection();
150
151             String JavaDoc sql = "INSERT INTO " + entryTable + " (" + entryId + ", " + entryName + ", " + entryState + ") VALUES (?,?,?)";
152
153             if (log.isDebugEnabled()) {
154                 log.debug("Executing SQL statement: " + sql);
155             }
156
157             stmt = conn.prepareStatement(sql);
158
159             long id = getNextEntrySequence(conn);
160             stmt.setLong(1, id);
161             stmt.setString(2, workflowName);
162             stmt.setInt(3, WorkflowEntry.CREATED);
163             stmt.executeUpdate();
164
165             return new SimpleWorkflowEntry(id, workflowName, WorkflowEntry.CREATED);
166         } catch (SQLException e) {
167             throw new StoreException("Error creating new workflow instance", e);
168         } finally {
169             cleanup(conn, stmt, null);
170         }
171     }
172
173     public List findCurrentSteps(long entryId) throws StoreException {
174         Connection conn = null;
175         PreparedStatement stmt = null;
176         ResultSet rset = null;
177         PreparedStatement stmt2 = null;
178
179         try {
180             conn = getConnection();
181
182             String JavaDoc sql = "SELECT " + stepId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + " FROM " + currentTable + " WHERE " + stepEntryId + " = ?";
183             String JavaDoc sql2 = "SELECT " + stepPreviousId + " FROM " + currentPrevTable + " WHERE " + stepId + " = ?";
184
185             if (log.isDebugEnabled()) {
186                 log.debug("Executing SQL statement: " + sql);
187             }
188
189             stmt = conn.prepareStatement(sql);
190
191             if (log.isDebugEnabled()) {
192                 log.debug("Executing SQL statement: " + sql2);
193             }
194
195             stmt2 = conn.prepareStatement(sql2);
196             stmt.setLong(1, entryId);
197
198             rset = stmt.executeQuery();
199
200             ArrayList currentSteps = new ArrayList();
201
202             while (rset.next()) {
203                 long id = rset.getLong(1);
204                 int stepId = rset.getInt(2);
205                 int actionId = rset.getInt(3);
206                 String JavaDoc owner = rset.getString(4);
207                 Date JavaDoc startDate = rset.getTimestamp(5);
208                 Date JavaDoc dueDate = rset.getTimestamp(6);
209                 Date JavaDoc finishDate = rset.getTimestamp(7);
210                 String JavaDoc status = rset.getString(8);
211                 String JavaDoc caller = rset.getString(9);
212
213                 ArrayList prevIdsList = new ArrayList();
214                 stmt2.setLong(1, id);
215
216                 ResultSet rs = stmt2.executeQuery();
217
218                 while (rs.next()) {
219                     long prevId = rs.getLong(1);
220                     prevIdsList.add(new Long JavaDoc(prevId));
221                 }
222
223                 long[] prevIds = new long[prevIdsList.size()];
224                 int i = 0;
225
226                 for (Iterator iterator = prevIdsList.iterator();
227                         iterator.hasNext();) {
228                     Long JavaDoc aLong = (Long JavaDoc) iterator.next();
229                     prevIds[i] = aLong.longValue();
230                     i++;
231                 }
232
233                 SimpleStep step = new SimpleStep(id, entryId, stepId, actionId, owner, startDate, dueDate, finishDate, status, prevIds, caller);
234                 currentSteps.add(step);
235             }
236
237             return currentSteps;
238         } catch (SQLException e) {
239             throw new StoreException("Unable to locate current steps for workflow instance #" + entryId, e);
240         } finally {
241             cleanup(null, stmt2, null);
242             cleanup(conn, stmt, rset);
243         }
244     }
245
246     public WorkflowEntry findEntry(long theEntryId) throws StoreException {
247         Connection conn = null;
248         PreparedStatement stmt = null;
249         ResultSet rset = null;
250
251         try {
252             conn = getConnection();
253
254             String JavaDoc sql = "SELECT " + entryName + ", " + entryState + " FROM " + entryTable + " WHERE " + entryId + " = ?";
255
256             if (log.isDebugEnabled()) {
257                 log.debug("Executing SQL statement: " + sql);
258             }
259
260             stmt = conn.prepareStatement(sql);
261             stmt.setLong(1, theEntryId);
262
263             rset = stmt.executeQuery();
264             rset.next();
265
266             String JavaDoc workflowName = rset.getString(1);
267             int state = rset.getInt(2);
268
269             return new SimpleWorkflowEntry(theEntryId, workflowName, state);
270         } catch (SQLException e) {
271             throw new StoreException("Error finding workflow instance #" + entryId);
272         } finally {
273             cleanup(conn, stmt, rset);
274         }
275     }
276
277     public List findHistorySteps(long entryId) throws StoreException {
278         Connection conn = null;
279         PreparedStatement stmt = null;
280         PreparedStatement stmt2 = null;
281         ResultSet rset = null;
282
283         try {
284             conn = getConnection();
285
286             String JavaDoc sql = "SELECT " + stepId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + " FROM " + historyTable + " WHERE " + stepEntryId + " = ? ORDER BY " + stepId + " DESC";
287             String JavaDoc sql2 = "SELECT " + stepPreviousId + " FROM " + historyPrevTable + " WHERE " + stepId + " = ?";
288
289             if (log.isDebugEnabled()) {
290                 log.debug("Executing SQL statement: " + sql);
291             }
292
293             stmt = conn.prepareStatement(sql);
294
295             if (log.isDebugEnabled()) {
296                 log.debug("Executing SQL statement: " + sql2);
297             }
298
299             stmt2 = conn.prepareStatement(sql2);
300             stmt.setLong(1, entryId);
301
302             rset = stmt.executeQuery();
303
304             ArrayList currentSteps = new ArrayList();
305
306             while (rset.next()) {
307                 long id = rset.getLong(1);
308                 int stepId = rset.getInt(2);
309                 int actionId = rset.getInt(3);
310                 String JavaDoc owner = rset.getString(4);
311                 Date JavaDoc startDate = rset.getTimestamp(5);
312                 Date JavaDoc dueDate = rset.getTimestamp(6);
313                 Date JavaDoc finishDate = rset.getTimestamp(7);
314                 String JavaDoc status = rset.getString(8);
315                 String JavaDoc caller = rset.getString(9);
316
317                 ArrayList prevIdsList = new ArrayList();
318                 stmt2.setLong(1, id);
319
320                 ResultSet rs = stmt2.executeQuery();
321
322                 while (rs.next()) {
323                     long prevId = rs.getLong(1);
324                     prevIdsList.add(new Long JavaDoc(prevId));
325                 }
326
327                 long[] prevIds = new long[prevIdsList.size()];
328                 int i = 0;
329
330                 for (Iterator iterator = prevIdsList.iterator();
331                         iterator.hasNext();) {
332                     Long JavaDoc aLong = (Long JavaDoc) iterator.next();
333                     prevIds[i] = aLong.longValue();
334                     i++;
335                 }
336
337                 SimpleStep step = new SimpleStep(id, entryId, stepId, actionId, owner, startDate, dueDate, finishDate, status, prevIds, caller);
338                 currentSteps.add(step);
339             }
340
341             return currentSteps;
342         } catch (SQLException e) {
343             throw new StoreException("Unable to locate history steps for workflow instance #" + entryId, e);
344         } finally {
345             cleanup(null, stmt2, null);
346             cleanup(conn, stmt, rset);
347         }
348     }
349
350     public void init(Map props) throws StoreException {
351         entrySequence = getInitProperty(props, "entry.sequence", "SELECT nextVal('seq_os_wfentry')");
352         stepSequence = getInitProperty(props, "step.sequence", "SELECT nextVal('seq_os_currentsteps')");
353         entryTable = getInitProperty(props, "entry.table", "OS_WFENTRY");
354         entryId = getInitProperty(props, "entry.id", "ID");
355         entryName = getInitProperty(props, "entry.name", "NAME");
356         entryState = getInitProperty(props, "entry.state", "STATE");
357         historyTable = getInitProperty(props, "history.table", "OS_HISTORYSTEP");
358         currentTable = getInitProperty(props, "current.table", "OS_CURRENTSTEP");
359         currentPrevTable = getInitProperty(props, "currentPrev.table", "OS_CURRENTSTEP_PREV");
360         historyPrevTable = getInitProperty(props, "historyPrev.table", "OS_HISTORYSTEP_PREV");
361         stepId = getInitProperty(props, "step.id", "ID");
362         stepEntryId = getInitProperty(props, "step.entryId", "ENTRY_ID");
363         stepStepId = getInitProperty(props, "step.stepId", "STEP_ID");
364         stepActionId = getInitProperty(props, "step.actionId", "ACTION_ID");
365         stepOwner = getInitProperty(props, "step.owner", "OWNER");
366         stepCaller = getInitProperty(props, "step.caller", "CALLER");
367         stepStartDate = getInitProperty(props, "step.startDate", "START_DATE");
368         stepFinishDate = getInitProperty(props, "step.finishDate", "FINISH_DATE");
369         stepDueDate = getInitProperty(props, "step.dueDate", "DUE_DATE");
370         stepStatus = getInitProperty(props, "step.status", "STATUS");
371         stepPreviousId = getInitProperty(props, "step.previousId", "PREVIOUS_ID");
372
373         String JavaDoc jndi = (String JavaDoc) props.get("datasource");
374
375         if (jndi != null) {
376             try {
377                 ds = (DataSource JavaDoc) lookup(jndi);
378
379                 if (ds == null) {
380                     ds = (DataSource JavaDoc) new javax.naming.InitialContext JavaDoc().lookup(jndi);
381                 }
382             } catch (Exception JavaDoc e) {
383                 throw new StoreException("Error looking up DataSource at " + jndi, e);
384             }
385         }
386     }
387
388     public Step markFinished(Step step, int actionId, Date JavaDoc finishDate, String JavaDoc status, String JavaDoc caller) throws StoreException {
389         Connection conn = null;
390         PreparedStatement stmt = null;
391
392         try {
393             conn = getConnection();
394
395             String JavaDoc sql = "UPDATE " + currentTable + " SET " + stepStatus + " = ?, " + stepActionId + " = ?, " + stepFinishDate + " = ?, " + stepCaller + " = ? WHERE " + stepId + " = ?";
396
397             if (log.isDebugEnabled()) {
398                 log.debug("Executing SQL statement: " + sql);
399             }
400
401             stmt = conn.prepareStatement(sql);
402             stmt.setString(1, status);
403             stmt.setInt(2, actionId);
404             stmt.setTimestamp(3, new Timestamp(finishDate.getTime()));
405             stmt.setString(4, caller);
406             stmt.setLong(5, step.getId());
407             stmt.executeUpdate();
408
409             SimpleStep theStep = (SimpleStep) step;
410             theStep.setActionId(actionId);
411             theStep.setFinishDate(finishDate);
412             theStep.setStatus(status);
413             theStep.setCaller(caller);
414
415             return theStep;
416         } catch (SQLException e) {
417             throw new StoreException("Unable to mark step finished for #" + step.getEntryId(), e);
418         } finally {
419             cleanup(conn, stmt, null);
420         }
421     }
422
423     public void moveToHistory(Step step) throws StoreException {
424         Connection conn = null;
425         PreparedStatement stmt = null;
426
427         try {
428             conn = getConnection();
429
430             String JavaDoc sql = "INSERT INTO " + historyTable + " (" + stepId + "," + stepEntryId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
431
432             if (log.isDebugEnabled()) {
433                 log.debug("Executing SQL statement: " + sql);
434             }
435
436             stmt = conn.prepareStatement(sql);
437             stmt.setLong(1, step.getId());
438             stmt.setLong(2, step.getEntryId());
439             stmt.setInt(3, step.getStepId());
440             stmt.setInt(4, step.getActionId());
441             stmt.setString(5, step.getOwner());
442             stmt.setTimestamp(6, new Timestamp(step.getStartDate().getTime()));
443
444             if (step.getFinishDate() != null) {
445                 stmt.setTimestamp(7, new Timestamp(step.getFinishDate().getTime()));
446             } else {
447                 stmt.setNull(7, Types.TIMESTAMP);
448             }
449
450             stmt.setString(8, step.getStatus());
451             stmt.setString(9, step.getCaller());
452             stmt.executeUpdate();
453
454             long[] previousIds = step.getPreviousStepIds();
455
456             if ((previousIds != null) && (previousIds.length > 0)) {
457                 sql = "INSERT INTO " + historyPrevTable + " (" + stepId + ", " + stepPreviousId + ") VALUES (?, ?)";
458                 log.debug("Executing SQL statement: " + sql);
459                 cleanup(null, stmt, null);
460                 stmt = conn.prepareStatement(sql);
461
462                 for (int i = 0; i < previousIds.length; i++) {
463                     long previousId = previousIds[i];
464                     stmt.setLong(1, step.getId());
465                     stmt.setLong(2, previousId);
466                     stmt.executeUpdate();
467                 }
468             }
469
470             sql = "DELETE FROM " + currentPrevTable + " WHERE " + stepId + " = ?";
471
472             if (log.isDebugEnabled()) {
473                 log.debug("Executing SQL statement: " + sql);
474             }
475
476             cleanup(null, stmt, null);
477             stmt = conn.prepareStatement(sql);
478             stmt.setLong(1, step.getId());
479             stmt.executeUpdate();
480
481             sql = "DELETE FROM " + currentTable + " WHERE " + stepId + " = ?";
482
483             if (log.isDebugEnabled()) {
484                 log.debug("Executing SQL statement: " + sql);
485             }
486
487             cleanup(null, stmt, null);
488             stmt = conn.prepareStatement(sql);
489             stmt.setLong(1, step.getId());
490             stmt.executeUpdate();
491         } catch (SQLException e) {
492             throw new StoreException("Unable to move current step to history step for #" + step.getEntryId(), e);
493         } finally {
494             cleanup(conn, stmt, null);
495         }
496     }
497
498     public List query(WorkflowExpressionQuery query) throws StoreException {
499         Expression expression = query.getExpression();
500
501         StringBuffer JavaDoc sel = new StringBuffer JavaDoc();
502         List values = new ArrayList();
503         String JavaDoc columnName = null;
504
505         if (expression.isNested()) {
506             columnName = buildNested((NestedExpression) expression, sel, values);
507         } else {
508             columnName = buildSimple((FieldExpression) expression, sel, values);
509         }
510
511         if (query.getSortOrder() != WorkflowExpressionQuery.SORT_NONE) {
512             sel.append(" ORDER BY ");
513             sel.append(fieldName(query.getOrderBy()));
514
515             if (query.getSortOrder() == WorkflowExpressionQuery.SORT_ASC) {
516                 sel.append(" ASC");
517             } else {
518                 sel.append(" DESC");
519             }
520         }
521
522         List results = doExpressionQuery(sel.toString(), columnName, values);
523
524         return results;
525     }
526
527     public List query(WorkflowQuery query) throws StoreException {
528         List results = new ArrayList();
529
530         // going to try to do all the comparisons in one query
531
String JavaDoc sel;
532         String JavaDoc table;
533
534         int qtype = query.getType();
535
536         if (qtype == 0) { // then not set, so look in sub queries
537
// 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
538
// but then again, why are there redundant tables in the first place? the data model should probably change
539

540             if (query.getLeft() != null) {
541                 qtype = query.getLeft().getType();
542             }
543         }
544
545         if (qtype == WorkflowQuery.CURRENT) {
546             table = currentTable;
547         } else {
548             table = historyTable;
549         }
550
551         sel = "SELECT DISTINCT(" + stepEntryId + ") FROM " + table + " WHERE ";
552         sel += queryWhere(query);
553
554         if (log.isDebugEnabled()) {
555             log.debug(sel);
556         }
557
558         Connection conn = null;
559         Statement stmt = null;
560         ResultSet rs = null;
561
562         try {
563             conn = getConnection();
564             stmt = conn.createStatement();
565             rs = stmt.executeQuery(sel);
566
567             while (rs.next()) {
568                 // get entryIds and add to results list
569
Long JavaDoc id = new Long JavaDoc(rs.getLong(stepEntryId));
570                 results.add(id);
571             }
572         } catch (SQLException ex) {
573             throw new StoreException("SQL Exception in query: " + ex.getMessage());
574         } finally {
575             cleanup(conn, stmt, rs);
576         }
577
578         return results;
579     }
580
581     protected Connection getConnection() throws SQLException {
582         closeConnWhenDone = true;
583
584         return ds.getConnection();
585     }
586
587     protected long getNextEntrySequence(Connection c) throws SQLException {
588         if (log.isDebugEnabled()) {
589             log.debug("Executing SQL statement: " + entrySequence);
590         }
591
592         PreparedStatement stmt = null;
593         ResultSet rset = null;
594
595         try {
596             stmt = c.prepareStatement(entrySequence);
597             rset = stmt.executeQuery();
598             rset.next();
599
600             long id = rset.getLong(1);
601
602             return id;
603         } finally {
604             cleanup(null, stmt, rset);
605         }
606     }
607
608     protected long getNextStepSequence(Connection c) throws SQLException {
609         if (log.isDebugEnabled()) {
610             log.debug("Executing SQL statement: " + stepSequence);
611         }
612
613         PreparedStatement stmt = null;
614         ResultSet rset = null;
615
616         try {
617             stmt = c.prepareStatement(stepSequence);
618             rset = stmt.executeQuery();
619             rset.next();
620
621             long id = rset.getLong(1);
622
623             return id;
624         } finally {
625             cleanup(null, stmt, rset);
626         }
627     }
628
629     protected void addPreviousSteps(Connection conn, long id, long[] previousIds) throws SQLException {
630         if ((previousIds != null) && (previousIds.length > 0)) {
631             if (!((previousIds.length == 1) && (previousIds[0] == 0))) {
632                 String JavaDoc sql = "INSERT INTO " + currentPrevTable + " (" + stepId + ", " + stepPreviousId + ") VALUES (?, ?)";
633                 log.debug("Executing SQL statement: " + sql);
634
635                 PreparedStatement stmt = conn.prepareStatement(sql);
636
637                 for (int i = 0; i < previousIds.length; i++) {
638                     long previousId = previousIds[i];
639                     stmt.setLong(1, id);
640                     stmt.setLong(2, previousId);
641                     stmt.executeUpdate();
642                 }
643
644                 cleanup(null, stmt, null);
645             }
646         }
647     }
648
649     protected void cleanup(Connection connection, Statement statement, ResultSet result) {
650         if (result != null) {
651             try {
652                 result.close();
653             } catch (SQLException ex) {
654                 log.error("Error closing resultset", ex);
655             }
656         }
657
658         if (statement != null) {
659             try {
660                 statement.close();
661             } catch (SQLException ex) {
662                 log.error("Error closing statement", ex);
663             }
664         }
665
666         if ((connection != null) && closeConnWhenDone) {
667             try {
668                 connection.close();
669             } catch (SQLException ex) {
670                 log.error("Error closing connection", ex);
671             }
672         }
673     }
674
675     protected long createCurrentStep(Connection conn, long entryId, int wfStepId, String JavaDoc owner, Date JavaDoc startDate, Date JavaDoc dueDate, String JavaDoc status) throws SQLException {
676         String JavaDoc sql = "INSERT INTO " + currentTable + " (" + stepId + "," + stepEntryId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + " ) VALUES (?, ?, ?, null, ?, ?, ?, null, ?, null)";
677
678         if (log.isDebugEnabled()) {
679             log.debug("Executing SQL statement: " + sql);
680         }
681
682         PreparedStatement stmt = conn.prepareStatement(sql);
683
684         long id = getNextStepSequence(conn);
685         stmt.setLong(1, id);
686         stmt.setLong(2, entryId);
687         stmt.setInt(3, wfStepId);
688         stmt.setString(4, owner);
689         stmt.setTimestamp(5, new Timestamp(startDate.getTime()));
690
691         if (dueDate != null) {
692             stmt.setTimestamp(6, new Timestamp(dueDate.getTime()));
693         } else {
694             stmt.setNull(6, Types.TIMESTAMP);
695         }
696
697         stmt.setString(7, status);
698         stmt.executeUpdate();
699         cleanup(null, stmt, null);
700
701         return id;
702     }
703
704     private String JavaDoc getInitProperty(Map props, String JavaDoc strName, String JavaDoc strDefault) {
705         Object JavaDoc o = props.get(strName);
706
707         if (o == null) {
708             return strDefault;
709         }
710
711         return (String JavaDoc) o;
712     }
713
714     private String JavaDoc buildNested(NestedExpression nestedExpression, StringBuffer JavaDoc sel, List values) {
715         sel.append("SELECT DISTINCT(");
716         sel.append(entryId);
717         sel.append(") FROM ");
718         sel.append(entryTable);
719
720         for (int i = 0; i < nestedExpression.getExpressionCount(); i++) {
721             Expression expression = nestedExpression.getExpression(i);
722
723             if (i == 0) {
724                 sel.append(" WHERE ");
725             } else {
726                 if (nestedExpression.getExpressionOperator() == NestedExpression.AND) {
727                     sel.append(" AND ");
728                 } else {
729                     sel.append(" OR ");
730                 }
731             }
732
733             if (expression.isNegate()) {
734                 sel.append(" NOT ");
735             }
736
737             sel.append(entryId);
738             sel.append(" IN (");
739
740             if (expression.isNested()) {
741                 this.buildNested((NestedExpression) nestedExpression.getExpression(i), sel, values);
742             } else {
743                 FieldExpression sub = (FieldExpression) nestedExpression.getExpression(i);
744                 this.buildSimple(sub, sel, values);
745             }
746
747             sel.append(")");
748         }
749
750         return (entryId);
751     }
752
753     private String JavaDoc buildSimple(FieldExpression fieldExpression, StringBuffer JavaDoc sel, List values) {
754         String JavaDoc table;
755         String JavaDoc columnName;
756
757         if (fieldExpression.getContext() == FieldExpression.CURRENT_STEPS) {
758             table = currentTable;
759             columnName = stepEntryId;
760         } else if (fieldExpression.getContext() == FieldExpression.HISTORY_STEPS) {
761             table = historyTable;
762             columnName = stepEntryId;
763         } else {
764             table = entryTable;
765             columnName = entryId;
766         }
767
768         sel.append("SELECT DISTINCT(");
769         sel.append(columnName);
770         sel.append(") FROM ");
771         sel.append(table);
772         sel.append(" WHERE ");
773         queryComparison(fieldExpression, sel, values);
774
775         return columnName;
776     }
777
778     private List doExpressionQuery(String JavaDoc sel, String JavaDoc columnName, List values) throws StoreException {
779         if (log.isDebugEnabled()) {
780             log.debug(sel);
781         }
782
783         Connection conn = null;
784         PreparedStatement stmt = null;
785         ResultSet rs = null;
786         List results = new ArrayList();
787
788         try {
789             conn = getConnection();
790             stmt = conn.prepareStatement(sel);
791
792             if (!values.isEmpty()) {
793                 for (int i = 1; i <= values.size(); i++) {
794                     stmt.setObject(i, values.get(i - 1));
795                 }
796             }
797
798             rs = stmt.executeQuery();
799
800             while (rs.next()) {
801                 // get entryIds and add to results list
802
Long JavaDoc id = new Long JavaDoc(rs.getLong(columnName));
803                 results.add(id);
804             }
805
806             return results;
807         } catch (SQLException ex) {
808             throw new StoreException("SQL Exception in query: " + ex.getMessage());
809         } finally {
810             cleanup(conn, stmt, rs);
811         }
812     }
813
814     private static String JavaDoc escape(String JavaDoc s) {
815         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(s);
816
817         char c;
818         char[] chars = s.toCharArray();
819
820         for (int i = 0; i < chars.length; i++) {
821             c = chars[i];
822
823             switch (c) {
824             case '\'':
825                 sb.insert(i, '\'');
826                 i++;
827
828                 break;
829
830             case '\\':
831                 sb.insert(i, '\\');
832                 i++;
833             }
834         }
835
836         return sb.toString();
837     }
838
839     private String JavaDoc fieldName(int field) {
840         switch (field) {
841         case FieldExpression.ACTION: // actionId
842
return stepActionId;
843
844         case FieldExpression.CALLER:
845             return stepCaller;
846
847         case FieldExpression.FINISH_DATE:
848             return stepFinishDate;
849
850         case FieldExpression.OWNER:
851             return stepOwner;
852
853         case FieldExpression.START_DATE:
854             return stepStartDate;
855
856         case FieldExpression.STEP: // stepId
857
return stepStepId;
858
859         case FieldExpression.STATUS:
860             return stepStatus;
861
862         case FieldExpression.STATE:
863             return entryState;
864
865         case FieldExpression.NAME:
866             return entryName;
867
868         default:
869             return "1";
870         }
871     }
872
873     private Object JavaDoc lookup(String JavaDoc location) throws NamingException JavaDoc {
874         try {
875             InitialContext JavaDoc context = new InitialContext JavaDoc();
876
877             try {
878                 return context.lookup(location);
879             } catch (NamingException JavaDoc e) {
880                 //ok, couldn't find it, look in env
881
return context.lookup("java:comp/env/" + location);
882             }
883         } catch (NamingException JavaDoc e) {
884             throw e;
885         }
886     }
887
888     private String JavaDoc queryComparison(WorkflowQuery query) {
889         Object JavaDoc value = query.getValue();
890         int operator = query.getOperator();
891         int field = query.getField();
892
893         //int type = query.getType();
894
String JavaDoc oper;
895
896         switch (operator) {
897         case WorkflowQuery.EQUALS:
898             oper = " = ";
899
900             break;
901
902         case WorkflowQuery.NOT_EQUALS:
903             oper = " <> ";
904
905             break;
906
907         case WorkflowQuery.GT:
908             oper = " > ";
909
910             break;
911
912         case WorkflowQuery.LT:
913             oper = " < ";
914
915             break;
916
917         default:
918             oper = " = ";
919         }
920
921         String JavaDoc left;
922         String JavaDoc right;
923
924         switch (field) {
925         case WorkflowQuery.ACTION: // actionId
926
left = stepActionId;
927
928             break;
929
930         case WorkflowQuery.CALLER:
931             left = stepCaller;
932
933             break;
934
935         case WorkflowQuery.FINISH_DATE:
936             left = stepFinishDate;
937
938             break;
939
940         case WorkflowQuery.OWNER:
941             left = stepOwner;
942
943             break;
944
945         case WorkflowQuery.START_DATE:
946             left = stepStartDate;
947
948             break;
949
950         case WorkflowQuery.STEP: // stepId
951
left = stepStepId;
952
953             break;
954
955         case WorkflowQuery.STATUS:
956             left = stepStatus;
957
958             break;
959
960         default:
961             left = "1";
962         }
963
964         if (value != null) {
965             right = "'" + escape(value.toString()) + "'";
966         } else {
967             right = "null";
968         }
969
970         return left + oper + right;
971     }
972
973     /**
974      * Method queryComparison
975      *
976      * @param expression a FieldExpression
977      * @param sel a StringBuffer
978      *
979      */

980     private void queryComparison(FieldExpression expression, StringBuffer JavaDoc sel, List values) {
981         Object JavaDoc value = expression.getValue();
982         int operator = expression.getOperator();
983         int field = expression.getField();
984
985         String JavaDoc oper;
986
987         switch (operator) {
988         case FieldExpression.EQUALS:
989
990             if (value == null) {
991                 oper = " IS ";
992             } else {
993                 oper = " = ";
994             }
995
996             break;
997
998         case FieldExpression.NOT_EQUALS:
999
1000            if (value == null) {
1001                oper = " IS NOT ";
1002            } else {
1003                oper = " <> ";
1004            }
1005
1006            break;
1007
1008        case FieldExpression.GT:
1009            oper = " > ";
1010
1011            break;
1012
1013        case FieldExpression.LT:
1014            oper = " < ";
1015
1016            break;
1017
1018        default:
1019            oper = " = ";
1020        }
1021
1022        String JavaDoc left = fieldName(field);
1023        String JavaDoc right = "?";
1024
1025        switch (field) {
1026        case FieldExpression.FINISH_DATE:
1027            values.add(new Timestamp(((Date JavaDoc) value).getTime()));
1028
1029            break;
1030
1031        case FieldExpression.START_DATE:
1032            values.add(new Timestamp(((Date JavaDoc) value).getTime()));
1033
1034            break;
1035
1036        default:
1037
1038            if (value == null) {
1039                right = "null";
1040            } else {
1041                values.add(value);
1042            }
1043        }
1044
1045        sel.append(left);
1046        sel.append(oper);
1047        sel.append(right);
1048    }
1049
1050    private String JavaDoc queryWhere(WorkflowQuery query) {
1051        if (query.getLeft() == null) {
1052            // leaf node
1053
return queryComparison(query);
1054        } else {
1055            int operator = query.getOperator();
1056            WorkflowQuery left = query.getLeft();
1057            WorkflowQuery right = query.getRight();
1058
1059            switch (operator) {
1060            case WorkflowQuery.AND:
1061                return "(" + queryWhere(left) + " AND " + queryWhere(right) + ")";
1062
1063            case WorkflowQuery.OR:
1064                return "(" + queryWhere(left) + " OR " + queryWhere(right) + ")";
1065
1066            case WorkflowQuery.XOR:
1067                return "(" + queryWhere(left) + " XOR " + queryWhere(right) + ")";
1068            }
1069        }
1070
1071        return ""; // not sure if we should throw an exception or how this should be handled
1072
}
1073}
1074
Popular Tags