View Javadoc

1   /*******************************************************************************
2    *  Copyright (c) 2005, 2006 Imola Informatica.
3    *  All rights reserved. This program and the accompanying materials
4    *  are made available under the terms of the LGPL License v2.1
5    *  which accompanies this distribution, and is available at
6    *  http://www.gnu.org/licenses/lgpl.html
7    *******************************************************************************/
8   /**
9    * 
10   */
11  package it.imolinfo.jbi4cics.connection.jdbc.util;
12  
13  import java.lang.reflect.InvocationHandler;
14  import java.lang.reflect.InvocationTargetException;
15  import java.lang.reflect.Method;
16  import java.sql.Connection;
17  import java.sql.ResultSet;
18  import java.sql.SQLException;
19  import java.sql.Statement;
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import javax.sql.rowset.CachedRowSet;
26  import com.sun.rowset.CachedRowSetImpl;
27  import it.imolinfo.jbi4cics.jbi.Messages;
28  import it.imolinfo.jbi4cics.Logger;
29  import it.imolinfo.jbi4cics.LoggerFactory;
30  
31  
32  
33  /**
34   * memorizza i set* appartenenti a Statement e gli altro metodi che ritornano void.
35   * quando si effettua la chiamata setconnected(true) allora vengono chiamati in sequenza i metodi memorizzati
36   * 
37   * i metodi che non possono essere cacheati devono essere chiamati quando si è in stato connesso
38   * @author raffaele
39   *
40   */
41  class StatementInvocationHandler implements InvocationHandler {
42    
43   /**
44    * The logger for this class and its instances.
45    */
46    private static final Logger LOG
47  	          = LoggerFactory.getLogger(StatementInvocationHandler.class);
48    
49    /**
50     * The responsible to translate localized messages.
51     */
52    private static final Messages MESSAGES
53            = Messages.getMessages(StatementInvocationHandler.class);
54    
55    private Connection connection;
56    private Statement underlyingStatement;
57    private boolean connected;
58    
59    private List<Command> commands=new ArrayList<Command>();
60    
61    /* pre imposto il default così si userà solo una firma per la creazione del resultset */
62    protected int resultSetType=ResultSet.TYPE_FORWARD_ONLY;
63    protected int resultSetConcurrency=ResultSet.CONCUR_READ_ONLY;
64    protected int resultSetHoldability=ResultSet.CLOSE_CURSORS_AT_COMMIT;
65  
66    /**
67     * 
68     */
69    public StatementInvocationHandler() {
70      super();
71    }
72    
73    /**
74     * @param resultSetType    The result set type
75     * @param resultSetConcurrency    The result set concurrency
76     */
77    public StatementInvocationHandler(int resultSetType, int resultSetConcurrency) {
78      super();
79      this.resultSetType=resultSetType;
80      this.resultSetConcurrency=resultSetConcurrency;
81    }
82    
83    /**
84     * @param resultSetType    The result set type
85     * @param resultSetConcurrency    The result set concurrency
86     * @param resultSetHoldability    The result set holdability
87     */
88    public StatementInvocationHandler(int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
89      super();
90      this.resultSetType=resultSetType;
91      this.resultSetConcurrency=resultSetConcurrency;
92      this.resultSetHoldability=resultSetHoldability;
93    }  
94  
95    /* (non-Javadoc)
96     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
97     */
98    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
99      
100     // gestione dei get; non possono essere cacheati
101     if (method.getName().startsWith("get")){
102       if ("getUnderlyingStatement".equals( method )){
103         return getUnderlyingStatement();
104       }
105       if (method.equals("getConnection")){
106         return getConnection();
107       }      
108       return handleGet(proxy,method,args);
109     }
110     // gestione dei set; possono essere cacheati
111     if (method.getName().startsWith("set")){
112       if (method.getName().equals("setConnection")){
113         setConnection((Connection)args[0]);
114         return null;
115       }
116       if (method.getName().equals("setConnected")){
117         setConnected(((Boolean)args[0]).booleanValue());
118         return null;
119       }  
120       return handleSet(proxy,method,args);
121       
122     }
123     
124     // gestione degli execute; non possono essere cacheati
125     if (method.getName().startsWith("execute")){
126       return handleExecute(proxy,method,args);
127     }
128     
129     if ("toString".equals(method.getName())){
130       return toString();
131     }
132     
133     // gli altri metodi ritonano void e possono essere cacheati
134     return handleOtherMethods(proxy,method,args);
135     
136   }
137   
138   public Object handleGet(Object proxy, Method method, Object[] args) throws SQLException{
139     if (isConnected()){
140       return invokeMethod(method, args);
141     }
142     else {
143       throw new SQLException("trying to invoke an execute method on a disconnected statement"); 
144     }
145   }
146   
147   public Object handleSet(Object proxy, Method method, Object[] args) throws SQLException{
148     if (isConnected()){
149       return invokeMethod(method, args);
150     }
151     else {
152       commands.add(new Command(method,args));
153       return null;
154     }
155   }  
156   
157   public Object handleExecute(Object proxy, Method method, Object[] args) throws SQLException{
158     if (isConnected()){
159       return invokeMethod(method, args);
160     }
161     else {
162       throw new SQLException(MESSAGES.getString("CIC000703_Error_invoking_execute_method")); 
163     }
164   }  
165   
166   public Object handleOtherMethods(Object proxy, Method method, Object[] args) throws SQLException{
167     if (isConnected()){
168       return invokeMethod(method, args);
169     }
170     else {
171       commands.add(new Command(method,args));
172       return null;
173     }
174   }  
175 
176   /**
177    * @return Returns the connection.
178    */
179   public Connection getConnection() {
180     return connection;
181   }
182 
183   /**
184    * @param conn The connection to set.
185    */
186   public void setConnection(Connection conn) {
187     this.connection = conn;
188   }
189 
190   /**
191    * @return Returns the connected.
192    */
193   public boolean isConnected() {
194     return connected;
195   }
196 
197   /**
198    * @param connected The connected to set.
199    * @throws SQLException The SQL exception
200    */
201   public void setConnected(boolean connected) throws SQLException {
202     if (connected){
203       if (connection!=null){
204         if (underlyingStatement==null){
205           //dobbiamo creare lo statement
206           underlyingStatement=createStatement();
207         }
208       }
209       else {
210         throw new SQLException(MESSAGES.getString("CIC000704_Error_setting_connected_state"));
211       }
212       // devo eseguire tutti i comandi memorizzati
213       for (Iterator<Command> i=commands.iterator();i.hasNext();){
214         Command command=i.next();
215         Method method=command.getMethod();
216         Object[] args=command.getArgs();
217         invokeMethod(method, args);        
218       }      
219     }
220     else {
221       // in questo modo il disconnected statement è riusabile
222       underlyingStatement=null;
223       connection=null;
224     }
225     this.connected = connected;
226   }
227 
228   /**
229    * @return Statement    The created statemant
230    * @throws SQLException    The SQL exception
231    */
232   protected Statement createStatement() throws SQLException {
233     return connection.createStatement(resultSetType,resultSetConcurrency,resultSetHoldability);
234   }
235 
236   /**
237    * @param method    The method
238    * @param args    The args
239    * @throws SQLException    The SQL Exception
240    * @return Object    The invoked  method
241    */
242   protected Object invokeMethod(Method method, Object[] args) throws SQLException {
243     try{
244       Object result=method.invoke(underlyingStatement,args);
245       if (result!=null && result instanceof ResultSet){
246         CachedRowSet cachedRowSet=new CachedRowSetImpl();
247         cachedRowSet.populate((ResultSet)result);
248         return cachedRowSet;        
249       }
250       else {
251         return result; 
252       }      
253     }
254     catch(IllegalAccessException e){
255       LOG.error("CIC000705_Illegal_access", new Object[]{method.toGenericString(), Arrays.toString(args), underlyingStatement}, e);
256       throw new SQLException(MESSAGES.getString("CIC000705_Illegal_access", new Object[]{method.toGenericString(), Arrays.toString(args), underlyingStatement}));
257     }
258     catch(InvocationTargetException e){
259       LOG.error("CIC000706_Target_exception", new Object[] {e.getTargetException()});
260       Throwable targetException=e.getTargetException();
261       if (targetException instanceof SQLException){ 
262         throw (SQLException)e.getTargetException();
263       }
264       else {
265         throw new SQLException(MESSAGES.getString("CIC000706_Target_exception", new Object[] {targetException.getMessage()}));
266       }
267     }
268   }
269   
270   /**
271    * @return A string
272    */
273   public String toString(){
274     return "connected: "+connected+ ", "+
275         (connected?"connection: "+connection+", ":"")+
276         (connected?"underlyingStatement: "+underlyingStatement+", ":"")+
277         (!connected?"stacked commands: "+Arrays.toString(commands.toArray()):"");
278   }
279 
280   /**
281    * @return Returns the underlyingStatement.
282    */
283   public Statement getUnderlyingStatement() {
284     return underlyingStatement;
285   }
286  
287   /**
288    * 
289    * @class Command     The commmand
290    */
291   private static class Command {
292     private Method method;
293     private Object[] args;
294     public Command(Method method, Object[] args) {
295       super();
296       // TODO Auto-generated constructor stub
297       this.method = method;
298       this.args = args;
299     }
300     
301     /**
302      * @return Returns the args.
303      */
304     public Object[] getArgs() {
305       return args;
306     }
307     
308     /**
309      * @param args The args to set.
310      */
311     public void setArgs(Object[] args) {
312       this.args = args;
313     }
314     /**
315      * @return Returns the method.
316      */
317     public Method getMethod() {
318       return method;
319     }
320     /**
321      * @param method The method to set.
322      */
323     public void setMethod(Method method) {
324       this.method = method;
325     }
326     
327     public String toString(){
328       return "method: "+method.toGenericString()+" ,"+
329              "args: "+Arrays.toString(args);
330     }
331   }
332 
333 }