KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > workflow > loader > JDBCWorkflowFactory


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

5 package com.opensymphony.workflow.loader;
6
7 import com.opensymphony.module.propertyset.PropertySet;
8
9 import com.opensymphony.workflow.FactoryException;
10 import com.opensymphony.workflow.FunctionProvider;
11
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14
15 import org.xml.sax.SAXException JavaDoc;
16
17 import java.io.*;
18
19 import java.sql.*;
20
21 import java.util.HashMap JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import javax.naming.InitialContext JavaDoc;
26 import javax.naming.NamingException JavaDoc;
27
28 import javax.sql.DataSource JavaDoc;
29
30
31 /**
32  * Workflow Factory that stores workflows in a database.
33  * The database requires a property called 'datasource' which is the JNDI
34  * name of the datasource for this factory.
35  * <p>
36  * Also required is a database table called OS_WORKFLOWDEFS with two columns,
37  * WF_NAME which contains the workflow name, and WF_DEFINITION which will contain the xml
38  * workflow descriptor, the latter can be either a TEXT or BINARY type.
39  * <p>
40  * Note that this class is provided as an example, and users are encouraged to use
41  * their own implementations that are more suited to their particular needs.
42  *
43  * @author Hubert Felber, Philipp Hug
44  * Date: May 01, 2003
45  * Time: 11:17:06 AM
46  */

47 public class JDBCWorkflowFactory extends XMLWorkflowFactory implements FunctionProvider {
48     //~ Static fields/initializers /////////////////////////////////////////////
49

50     private static final Log log = LogFactory.getLog(JDBCWorkflowFactory.class);
51     final static String JavaDoc wfTable = "OS_WORKFLOWDEFS";
52     final static String JavaDoc wfName = "WF_NAME";
53     final static String JavaDoc wfDefinition = "WF_DEFINITION";
54
55     //~ Instance fields ////////////////////////////////////////////////////////
56

57     protected DataSource JavaDoc ds;
58     protected Map JavaDoc workflows;
59     protected boolean reload;
60
61     //~ Methods ////////////////////////////////////////////////////////////////
62

63     public WorkflowDescriptor getWorkflow(String JavaDoc name) throws FactoryException {
64         WfConfig c = (WfConfig) workflows.get(name);
65
66         if (c == null) {
67             throw new RuntimeException JavaDoc("Unknown workflow name \"" + name + "\"");
68         }
69
70         if (log.isDebugEnabled()) {
71             log.debug("getWorkflow " + name + " descriptor=" + c.descriptor);
72         }
73
74         if (c.descriptor != null) {
75             if (reload) {
76                 //@todo check timestamp
77
try {
78                     c.descriptor = load(c.wfName);
79                 } catch (FactoryException e) {
80                     throw e;
81                 } catch (Exception JavaDoc e) {
82                     throw new FactoryException("Error reloading workflow", e);
83                 }
84             }
85         } else {
86             if (log.isDebugEnabled()) {
87                 try {
88                     c.descriptor = load(c.wfName);
89                 } catch (FactoryException e) {
90                     throw e;
91                 } catch (Exception JavaDoc e) {
92                     throw new FactoryException("Error loading workflow", e);
93                 }
94             }
95         }
96
97         return c.descriptor;
98     }
99
100     public String JavaDoc[] getWorkflowNames() {
101         int i = 0;
102         String JavaDoc[] res = new String JavaDoc[workflows.keySet().size()];
103         Iterator JavaDoc it = workflows.keySet().iterator();
104
105         while (it.hasNext()) {
106             res[i++] = (String JavaDoc) it.next();
107         }
108
109         return res;
110     }
111
112     public void execute(Map JavaDoc transientVars, Map JavaDoc args, PropertySet ps) {
113         String JavaDoc name = (String JavaDoc) args.get("name");
114         WorkflowDescriptor wfds = (WorkflowDescriptor) transientVars.get("descriptor");
115
116         try {
117             saveWorkflow(name, wfds, false);
118         } catch (Exception JavaDoc e) {
119         }
120     }
121
122     public void initDone() throws FactoryException {
123         Connection conn = null;
124
125         try {
126             init();
127             reload = getProperties().getProperty("reload", "false").equalsIgnoreCase("true");
128
129             conn = ds.getConnection();
130
131             PreparedStatement ps = conn.prepareStatement("SELECT " + wfName + "," + wfDefinition + " FROM " + wfTable);
132             ResultSet rs = ps.executeQuery();
133
134             while (rs.next()) {
135                 String JavaDoc name = rs.getString(1);
136                 WfConfig config = new WfConfig(name);
137                 workflows.put(rs.getString(1), config);
138             }
139
140             rs.close();
141             ps.close();
142         } catch (Exception JavaDoc e) {
143             throw new FactoryException("Could not read workflow names from datasource", e);
144         } finally {
145             try {
146                 conn.close();
147             } catch (Exception JavaDoc ex) {
148             }
149         }
150     }
151
152     public byte[] read(String JavaDoc workflowname) throws SQLException {
153         byte[] wf = new byte[0];
154
155         Connection conn = null;
156
157         try {
158             conn = ds.getConnection();
159
160             PreparedStatement ps = conn.prepareStatement("SELECT " + wfDefinition + " FROM " + wfTable + " WHERE " + wfName + " = ?");
161             ps.setString(1, workflowname);
162
163             ResultSet rs = ps.executeQuery();
164
165             if (rs.next()) {
166                 wf = rs.getBytes(1);
167             }
168
169             rs.close();
170             ps.close();
171         } finally {
172             try {
173                 conn.close();
174             } catch (Exception JavaDoc ex) {
175             }
176         }
177
178         return wf;
179     }
180
181     public boolean removeWorkflow(String JavaDoc name) throws FactoryException {
182         boolean removed = false;
183
184         try {
185             Connection conn = ds.getConnection();
186             PreparedStatement ps = conn.prepareStatement("DELETE FROM " + wfTable + " WHERE " + wfName + " = ?");
187             ps.setString(1, name);
188
189             int rows = ps.executeUpdate();
190
191             if (rows == 1) {
192                 removed = true;
193                 workflows.remove(name);
194             }
195
196             ps.close();
197             conn.close();
198         } catch (SQLException e) {
199             throw new FactoryException("Unable to remove workflow: " + e.toString(), e);
200         }
201
202         return removed;
203     }
204
205     public boolean saveWorkflow(String JavaDoc name, WorkflowDescriptor descriptor, boolean replace) throws FactoryException {
206         WfConfig c = (WfConfig) workflows.get(name);
207
208         if ((c != null) && !replace) {
209             return false;
210         }
211
212         ByteArrayOutputStream bout = new ByteArrayOutputStream();
213         Writer out = new OutputStreamWriter(bout);
214
215         PrintWriter writer = new PrintWriter(out);
216         writer.println(WorkflowDescriptor.XML_HEADER);
217         writer.println(WorkflowDescriptor.DOCTYPE_DECL);
218         descriptor.writeXML(writer, 0);
219         writer.flush();
220         writer.close();
221
222         //@todo is a backup necessary?
223
try {
224             return write(name, bout.toByteArray());
225         } catch (SQLException e) {
226             throw new FactoryException("Unable to save workflow: " + e.toString(), e);
227         } finally {
228             WfConfig config = new WfConfig(name);
229             workflows.put(name, config);
230         }
231     }
232
233     public boolean write(String JavaDoc workflowname, byte[] wf) throws SQLException {
234         boolean written = false;
235         Connection conn = null;
236
237         try {
238             conn = ds.getConnection();
239
240             PreparedStatement ps;
241
242             if (exists(workflowname, conn)) {
243                 ps = conn.prepareStatement("UPDATE " + wfTable + " SET " + wfDefinition + " = ?" + "WHERE " + wfName + "= ?");
244
245                 try {
246                     ps.setBytes(1, wf);
247                 } catch (Exception JavaDoc e) {
248                 }
249
250                 ps.setString(2, workflowname);
251             } else {
252                 ps = conn.prepareStatement("INSERT INTO " + wfTable + " (" + wfName + ", " + wfDefinition + ") VALUES (?, ?)");
253                 ps.setString(1, workflowname);
254
255                 try {
256                     ps.setBytes(2, wf);
257                 } catch (Exception JavaDoc e) {
258                 }
259             }
260
261             ps.executeUpdate();
262             ps.close();
263             conn.close();
264             written = true;
265         } finally {
266             try {
267                 conn.close();
268             } catch (Exception JavaDoc e) {
269             }
270         }
271
272         return written;
273     }
274
275     private boolean exists(String JavaDoc workflowname, Connection conn) {
276         boolean exists = false;
277
278         try {
279             PreparedStatement ps = conn.prepareStatement("SELECT " + wfName + " FROM " + wfTable + " WHERE " + wfName + " = ?");
280             ps.setString(1, workflowname);
281
282             ResultSet rs = ps.executeQuery();
283
284             if (rs.next()) {
285                 exists = true;
286             }
287
288             rs.close();
289             ps.close();
290         } catch (SQLException e) {
291             log.fatal("Could not check if [" + workflowname + "] exists", e);
292         }
293
294         return exists;
295     }
296
297     private void init() throws NamingException JavaDoc {
298         workflows = new HashMap JavaDoc();
299
300         ds = (DataSource JavaDoc) new InitialContext JavaDoc().lookup(getProperties().getProperty("datasource"));
301     }
302
303     private WorkflowDescriptor load(final String JavaDoc wfName) throws IOException, SAXException JavaDoc, FactoryException {
304         byte[] wf = new byte[0];
305
306         try {
307             wf = read(wfName);
308         } catch (SQLException e) {
309             throw new FactoryException("Error loading workflow:" + e, e);
310         }
311
312         ByteArrayInputStream is = new ByteArrayInputStream(wf);
313
314         return WorkflowLoader.load(is);
315     }
316
317     //~ Inner Classes //////////////////////////////////////////////////////////
318

319     class WfConfig {
320         String JavaDoc wfName;
321         WorkflowDescriptor descriptor;
322         long lastModified;
323
324         public WfConfig(String JavaDoc name) {
325             wfName = name;
326         }
327     }
328 }
329
Popular Tags