OSDN Git Service

63a92354f23939a6a53674d72720b766e2b8ce45
[luz/luz.git] / luz2 / src / com / lavans / luz2 / sql / cluster / ClusterStatement.java
1 /* $Id: ClusterStatement.java 94 2008-12-18 11:07:17Z dobashi $\r
2  * create: 2004/09/15\r
3  * (c)2004 Lavans Networks Inc. All Rights Reserved.\r
4  */\r
5 package com.lavans.luz2.sql.cluster;\r
6 \r
7 import java.lang.reflect.InvocationTargetException;\r
8 import java.sql.Connection;\r
9 import java.sql.ResultSet;\r
10 import java.sql.SQLException;\r
11 import java.sql.SQLWarning;\r
12 import java.sql.Statement;\r
13 import java.util.ArrayList;\r
14 import java.util.List;\r
15 \r
16 import org.apache.commons.logging.Log;\r
17 import org.apache.commons.logging.LogFactory;\r
18 \r
19 /**\r
20  * @author dobashi\r
21  * @version 1.00\r
22  */\r
23 public class ClusterStatement implements Statement, ClusterStatementInterface{\r
24         /** Messageクラスに移動? */\r
25         protected static final String MSG_ERR_REUPDATE="Statementの再生成に失敗。";\r
26         protected static final String MSG_WARN_SWITCH_DB="障害が出たので接続先を切り替えます。";\r
27 \r
28         /** 処理移譲先。 */\r
29         private Statement st=null;\r
30 \r
31         /** コネクション。障害時に別のStaementを作るよう依頼する。 */\r
32         private ClusterConnection con = null;\r
33 \r
34         /**\r
35          * 保存しておくメソッドのリスト。\r
36          * 障害が発生した場合、ClusterPreparedStatementに対する操作を操作が行われた\r
37          * 順序どおりに再実行する必要がある。\r
38          */\r
39         private List<CalledMethod> methodList = null;\r
40 \r
41         /** 実行されたsql文。障害時にResultSetを再生成するのに必要。 */\r
42         private String sql = null;\r
43 \r
44         /** ロガー。debug用 */\r
45         private static Log logger = LogFactory.getLog(ClusterStatement.class);\r
46 \r
47         /**\r
48          * コンストラクタ。\r
49          * @param st\r
50          */\r
51         public ClusterStatement(ClusterConnection con, Statement st){\r
52                 this.con = con;\r
53                 this.st = st;\r
54                 methodList = new ArrayList<CalledMethod>();\r
55         }\r
56 \r
57         /**\r
58          * DB切替時、新たに取得したStatementに対して\r
59          * 更新処理を再実行する。\r
60          * @param\r
61          */\r
62         public void reupdateStatement(Statement st) throws SQLException{\r
63                 try { this.st.close(); } catch (SQLException se) {}\r
64                 this.st = st;\r
65 \r
66                 for(int i=0; i<methodList.size(); i++){\r
67                         CalledMethod calledMethod = methodList.get(i);\r
68                         try{\r
69                                 calledMethod.invoke(st);        // 戻り値は無視して良い\r
70                         }catch (Exception e) {\r
71                                 logger.error("reupdate failed",e);\r
72                                 throw new SQLException(MSG_ERR_REUPDATE);\r
73                         }\r
74                 }\r
75         }\r
76 \r
77         /**\r
78          * クラスタリング対応のメソッド実行処理。\r
79          * @param methodName\r
80          * @param args\r
81          * @return\r
82          * @throws SQLException\r
83          */\r
84         private Object clusterCall(String methodName, Object[] args, Class<?>[] parameterTypes, boolean saveMethod) throws SQLException{\r
85                 Object result = null;\r
86                 CalledMethod calledMethod = new CalledMethod(methodName, args, parameterTypes);\r
87 \r
88                 logger.debug(calledMethod.toString());\r
89 \r
90                 try{\r
91                         result = calledMethod.invoke(st);\r
92                 }catch (Exception e) {\r
93                         logger.warn(MSG_WARN_SWITCH_DB, e);\r
94                         // try { st.close(); } catch (SQLException se) {}\r
95                         con.notifyError(this);  // エラーを通知。ここでstは新しいものになっているはず。\r
96                         try{\r
97                                 // 再度実行。ここでもさらにエラーがでるならSQLExceptionにラップする。\r
98                                 result = calledMethod.invoke(st);\r
99                         }catch (InvocationTargetException e2) {\r
100                                 // 例外がSQLExceptionならそのままthrow\r
101                                 Throwable t = e2.getTargetException();\r
102                                 if(t instanceof SQLException){\r
103                                         throw (SQLException)t;\r
104                                 }\r
105                                 // それ以外ならwrapしてthrow\r
106                                 SQLException sqle = new SQLException();\r
107                                 sqle.initCause(e2.getTargetException());\r
108                                 throw sqle;\r
109                         }catch (Exception e2) {\r
110                                 SQLException sqle = new SQLException();\r
111                                 sqle.initCause(e2);\r
112                                 throw sqle;\r
113                         }\r
114                 }\r
115                 if(saveMethod){\r
116                         methodList.add(calledMethod);\r
117                 }\r
118 \r
119                 return result;\r
120         }\r
121 \r
122         /**\r
123          * @see java.sql.Statement#executeQuery(java.lang.String)\r
124          */\r
125         public ResultSet getAnotherResultSet() throws SQLException {\r
126                 logger.debug("Redo st.executeQuery and get ResultSet.\n"+ sql);\r
127 \r
128                 // resultSet内で障害を検知したので、再度コネクションを張り直す。\r
129                 con.notifyError(this);  // エラーを通知。ここでstは新しいものになっているはず。\r
130                 ResultSet rs = st.executeQuery(sql);\r
131 \r
132                 return rs;\r
133         }\r
134 \r
135         /**\r
136          * @see java.sql.Statement#executeQuery(java.lang.String)\r
137          */\r
138         public ResultSet executeQuery(String sql) throws SQLException {\r
139                 ResultSet rs = (ResultSet)clusterCall("executeQuery", new Object[]{sql}, new Class[]{String.class}, true);\r
140 \r
141                 return new ClusterResultSet(this,rs);\r
142         }\r
143 \r
144         /**\r
145          * @see java.sql.Statement#executeUpdate(java.lang.String)\r
146          */\r
147         public int executeUpdate(String sql) throws SQLException {\r
148                 return ((Integer)clusterCall("executeUpdate", new Object[]{sql}, new Class[]{String.class}, true)).intValue();\r
149         }\r
150 \r
151         /**\r
152          * @see java.sql.Statement#executeUpdate(java.lang.String, int)\r
153          */\r
154         public int executeUpdate(String sql, int autoGeneratedKeys)\r
155                 throws SQLException {\r
156                 return ((Integer)clusterCall("executeUpdate", new Object[]{sql, new Integer(autoGeneratedKeys)},\r
157                                 new Class[]{String.class, Integer.TYPE}, true)).intValue();\r
158         }\r
159 \r
160         /**\r
161          * @see java.sql.Statement#executeUpdate(java.lang.String, int[])\r
162          */\r
163         public int executeUpdate(String sql, int[] columnIndexes)\r
164                 throws SQLException {\r
165                 return ((Integer)clusterCall("executeUpdate", new Object[]{sql, columnIndexes},\r
166                                 new Class[]{String.class, int[].class}, true)).intValue();\r
167         }\r
168 \r
169         /**\r
170          * @see java.sql.Statement#executeUpdate(java.lang.String, java.lang.String[])\r
171          */\r
172         public int executeUpdate(String sql, String[] columnNames)\r
173                 throws SQLException {\r
174                 return ((Integer)clusterCall("executeUpdate", new Object[]{sql, columnNames},\r
175                                  new Class[]{String.class, String[].class}, true)).intValue();\r
176         }\r
177 \r
178         /**\r
179          * @see java.sql.Statement#execute(java.lang.String, int)\r
180          */\r
181         public boolean execute(String sql, int autoGeneratedKeys)\r
182                 throws SQLException {\r
183                 return ((Boolean)clusterCall("execute", new Object[]{sql, new Integer(autoGeneratedKeys)},\r
184                                  new Class[]{String.class, Integer.TYPE}, true)).booleanValue();\r
185         }\r
186 \r
187         /**\r
188          * @see java.sql.Statement#execute(java.lang.String)\r
189          */\r
190         public boolean execute(String sql) throws SQLException {\r
191                 return ((Boolean)clusterCall("execute", new Object[]{sql},\r
192                                  new Class[]{String.class}, true)).booleanValue();\r
193         }\r
194 \r
195         /**\r
196          * @see java.sql.Statement#execute(java.lang.String, int[])\r
197          */\r
198         public boolean execute(String sql, int[] columnIndexes)\r
199                 throws SQLException {\r
200                         return ((Boolean)clusterCall("execute", new Object[]{sql, columnIndexes},\r
201                                          new Class[]{String.class, int[].class}, true)).booleanValue();\r
202         }\r
203 \r
204         /**\r
205          * @see java.sql.Statement#execute(java.lang.String, java.lang.String[])\r
206          */\r
207         public boolean execute(String sql, String[] columnNames)\r
208                 throws SQLException {\r
209                 return ((Boolean)clusterCall("execute", new Object[]{sql, columnNames},\r
210                                  new Class[]{String.class, String[].class}, true)).booleanValue();\r
211         }\r
212 \r
213         /**\r
214          * @see java.sql.Statement#getFetchDirection()\r
215          */\r
216         public int getFetchDirection() throws SQLException {\r
217                 return ((Integer)clusterCall("getFetchDirection", null, null, false)).intValue();\r
218         }\r
219 \r
220         /**\r
221          * @see java.sql.Statement#getFetchSize()\r
222          */\r
223         public int getFetchSize() throws SQLException {\r
224                 return ((Integer)clusterCall("getFetchSize", null, null, false)).intValue();\r
225         }\r
226 \r
227         /**\r
228          * @see java.sql.Statement#getMaxFieldSize()\r
229          */\r
230         public int getMaxFieldSize() throws SQLException {\r
231                 return ((Integer)clusterCall("getMaxFieldSize", null, null, false)).intValue();\r
232         }\r
233 \r
234         /**\r
235          * @see java.sql.Statement#getMaxRows()\r
236          */\r
237         public int getMaxRows() throws SQLException {\r
238                 return ((Integer)clusterCall("getMaxRows", null, null, false)).intValue();\r
239         }\r
240 \r
241         /**\r
242          * @see java.sql.Statement#getQueryTimeout()\r
243          */\r
244         public int getQueryTimeout() throws SQLException {\r
245                 return ((Integer)clusterCall("getQueryTimeout", null, null, false)).intValue();\r
246         }\r
247 \r
248         /**\r
249          * @see java.sql.Statement#getResultSetConcurrency()\r
250          */\r
251         public int getResultSetConcurrency() throws SQLException {\r
252                 return ((Integer)clusterCall("getResultSetConcurrency", null, null, false)).intValue();\r
253         }\r
254 \r
255         /**\r
256          * @see java.sql.Statement#getResultSetHoldability()\r
257          */\r
258         public int getResultSetHoldability() throws SQLException {\r
259                 return ((Integer)clusterCall("getResultSetConcurrency", null, null, false)).intValue();\r
260         }\r
261 \r
262         /**\r
263          * @see java.sql.Statement#getResultSetType()\r
264          */\r
265         public int getResultSetType() throws SQLException {\r
266                 return ((Integer)clusterCall("getResultSetType", null, null, false)).intValue();\r
267         }\r
268 \r
269         /**\r
270          * @see java.sql.Statement#getUpdateCount()\r
271          */\r
272         public int getUpdateCount() throws SQLException {\r
273                 return ((Integer)clusterCall("getUpdateCount", null, null, false)).intValue();\r
274         }\r
275 \r
276         /**\r
277          *\r
278          * @see java.sql.Statement#cancel()\r
279          */\r
280         public void cancel() throws SQLException {\r
281                 clusterCall("cancel", null, null, true);\r
282         }\r
283 \r
284         /**\r
285          * @see java.sql.Statement#clearBatch()\r
286          */\r
287         public void clearBatch() throws SQLException {\r
288                 clusterCall("clearBatch", null, null, true);\r
289                 st.clearBatch();\r
290         }\r
291 \r
292         /**\r
293          * @see java.sql.Statement#clearWarnings()\r
294          */\r
295         public void clearWarnings() throws SQLException {\r
296                 clusterCall("clearWarnings", null, null, true);\r
297                 st.clearWarnings();\r
298         }\r
299 \r
300         /**\r
301          * @see java.sql.Statement#close()\r
302          */\r
303         public void close() throws SQLException {\r
304                 clusterCall("close", null, null, true);\r
305                 st.close();\r
306                 con.remove(this);\r
307         }\r
308 \r
309         /**\r
310          * @see java.sql.Statement#getMoreResults()\r
311          */\r
312         public boolean getMoreResults() throws SQLException {\r
313                 return ((Boolean)clusterCall("getMoreResults", null, null, false)).booleanValue();\r
314         }\r
315 \r
316         /**\r
317          * @see java.sql.Statement#executeBatch()\r
318          */\r
319         public int[] executeBatch() throws SQLException {\r
320                 return (int[])clusterCall("executeBatch", null, null, true);\r
321         }\r
322 \r
323         /**\r
324          * @see java.sql.Statement#setFetchDirection(int)\r
325          */\r
326         public void setFetchDirection(int direction) throws SQLException {\r
327                 clusterCall("setFetchDirection", new Object[]{new Integer(direction)}, new Class[]{Integer.TYPE}, true);\r
328         }\r
329 \r
330         /**\r
331          * @see java.sql.Statement#setFetchSize(int)\r
332          */\r
333         public void setFetchSize(int rows) throws SQLException {\r
334                 clusterCall("setFetchSize", new Object[]{new Integer(rows)}, new Class[]{Integer.TYPE}, true);\r
335         }\r
336 \r
337         /**\r
338          * @see java.sql.Statement#setMaxFieldSize(int)\r
339          */\r
340         public void setMaxFieldSize(int max) throws SQLException {\r
341                 clusterCall("setMaxFieldSize", new Object[]{new Integer(max)}, new Class[]{Integer.TYPE}, true);\r
342         }\r
343 \r
344         /**\r
345          * @see java.sql.Statement#setMaxRows(int)\r
346          */\r
347         public void setMaxRows(int max) throws SQLException {\r
348                 clusterCall("setMaxRows", new Object[]{new Integer(max)}, new Class[]{Integer.TYPE}, true);\r
349         }\r
350 \r
351         /**\r
352          * @see java.sql.Statement#setQueryTimeout(int)\r
353          */\r
354         public void setQueryTimeout(int seconds) throws SQLException {\r
355                 clusterCall("setQueryTimeout", new Object[]{new Integer(seconds)}, new Class[]{Integer.TYPE}, true);\r
356         }\r
357 \r
358         /**\r
359          * @see java.sql.Statement#getMoreResults(int)\r
360          */\r
361         public boolean getMoreResults(int current) throws SQLException {\r
362                 return ((Boolean)clusterCall("getMoreResults",  new Object[]{new Integer(current)}, new Class[]{Integer.TYPE}, false)).booleanValue();\r
363         }\r
364 \r
365         /**\r
366          * @see java.sql.Statement#setEscapeProcessing(boolean)\r
367          */\r
368         public void setEscapeProcessing(boolean enable) throws SQLException {\r
369                 clusterCall("setFetchDirection", new Object[]{new Boolean(enable)}, new Class[]{Boolean.TYPE}, true);\r
370         }\r
371 \r
372 \r
373         /**\r
374          * @see java.sql.Statement#addBatch(java.lang.String)\r
375          */\r
376         public void addBatch(String sql) throws SQLException {\r
377                 clusterCall("addBatch", new Object[]{sql}, new Class[]{String.class}, true);\r
378         }\r
379 \r
380         /**\r
381          * @see java.sql.Statement#setCursorName(java.lang.String)\r
382          */\r
383         public void setCursorName(String name) throws SQLException {\r
384                 clusterCall("setCursorName", new Object[]{name}, new Class[]{String.class}, true);\r
385         }\r
386 \r
387 \r
388         /**\r
389          * @see java.sql.Statement#getConnection()\r
390          */\r
391         public Connection getConnection() throws SQLException {\r
392                 return con;\r
393 //              return (Connection)clusterCall("getConnection",  null, false);\r
394         }\r
395 \r
396         /**\r
397          * @see java.sql.Statement#getGeneratedKeys()\r
398          */\r
399         public ResultSet getGeneratedKeys() throws SQLException {\r
400                 return (ResultSet)clusterCall("getGeneratedKeys", null, null, false);\r
401         }\r
402 \r
403         /**\r
404          * @see java.sql.Statement#getResultSet()\r
405          */\r
406         public ResultSet getResultSet() throws SQLException {\r
407                 return (ResultSet)clusterCall("getResultSet", null, null, false);\r
408         }\r
409 \r
410         /**\r
411          * @see java.sql.Statement#getWarnings()\r
412          */\r
413         public SQLWarning getWarnings() throws SQLException {\r
414                 return (SQLWarning)clusterCall("getWarnings", null, null, false);\r
415         }\r
416         /**\r
417          * @return\r
418          * @throws SQLException\r
419          * @see java.sql.Statement#isClosed()\r
420          */\r
421         public boolean isClosed() throws SQLException {\r
422                 return st.isClosed();\r
423         }\r
424 \r
425         /**\r
426          * @return\r
427          * @throws SQLException\r
428          * @see java.sql.Statement#isPoolable()\r
429          */\r
430         public boolean isPoolable() throws SQLException {\r
431                 return st.isPoolable();\r
432         }\r
433 \r
434         /**\r
435          * @param iface\r
436          * @return\r
437          * @throws SQLException\r
438          * @see java.sql.Wrapper#isWrapperFor(java.lang.Class)\r
439          */\r
440         public boolean isWrapperFor(Class<?> iface) throws SQLException {\r
441                 return st.isWrapperFor(iface);\r
442         }\r
443 \r
444         /**\r
445          * @param poolable\r
446          * @throws SQLException\r
447          * @see java.sql.Statement#setPoolable(boolean)\r
448          */\r
449         public void setPoolable(boolean poolable) throws SQLException {\r
450                 st.setPoolable(poolable);\r
451         }\r
452 \r
453         /**\r
454          * @param <T>\r
455          * @param iface\r
456          * @return\r
457          * @throws SQLException\r
458          * @see java.sql.Wrapper#unwrap(java.lang.Class)\r
459          */\r
460         @SuppressWarnings("unchecked")\r
461         public <T> T unwrap(Class<T> iface) throws SQLException {\r
462                 return (T)this;\r
463         }\r
464 }\r