001: /*
002: *
003: * JOnAS: Java(TM) Open Application Server
004: * Copyright (C) 1999 Bull S.A.
005: * Contact: jonas-team@objectweb.org
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020: * USA
021: *
022: * --------------------------------------------------------------------------
023: * $Id: JonasSQLWrapper.java 6661 2005-04-28 08:43:27Z benoitf $
024: * --------------------------------------------------------------------------
025: */
026:
027: package org.objectweb.jonas.resource;
028:
029: import java.lang.reflect.InvocationHandler;
030: import java.lang.reflect.Method;
031: import java.lang.reflect.Proxy;
032: import java.sql.SQLException;
033: import java.util.ArrayList;
034: import java.util.List;
035:
036: import org.objectweb.util.monolog.api.BasicLevel;
037: import org.objectweb.util.monolog.api.Logger;
038:
039: /**
040: * SQL Connection Wrapper
041: *
042: * @author Eric Hardesty
043: * Contributor(s):
044: */
045: public class JonasSQLWrapper implements InvocationHandler {
046:
047: /**
048: * Number of fixed arguments
049: */
050: private static final int PROXY_FIXED_ARGS = 3;
051: /**
052: * Real connection object
053: */
054: private Object connection = null;
055: /**
056: * Connection manager holding the PreparedStatement cache
057: */
058: private SQLManager conman = null;
059: /**
060: * MCInfo for the connection
061: */
062: private MCInfo mci = null;
063: /**
064: * Userid of the connection
065: */
066: private String user = null;
067: /**
068: * Logger object
069: */
070: private Logger trace = null;
071:
072: /**
073: * Determine if statement is still valid
074: */
075: private boolean invalid = false;
076: /**
077: * Determine if statement cache is in use
078: */
079: private boolean supportsPreparedCache = true;
080:
081: /**
082: * PreparedStatement wrapper
083: * @param pConn JDBC connection object
084: * @param pMci MCInfo object associated with the connection
085: * @param pConman SQLManager object holding PreparedStatement cache
086: * @param pTrace Logger object to use
087: * @throws Exception if an error occurs
088: */
089: public JonasSQLWrapper(Object pConn, MCInfo pMci,
090: SQLManager pConman, Logger pTrace) throws Exception {
091: connection = pConn;
092: mci = pMci;
093: conman = pConman;
094: trace = pTrace;
095: user = mci.mc.getMetaData().getUserName();
096: }
097:
098: /**
099: * Returns a proxy for the sql Connection
100: *
101: * @param pConn JDBC connection object
102: * @param pMci MCInfo object associated with the connection
103: * @param pConman SQLManager object holding PreparedStatement cache
104: * @param pTrace Logger object to use
105: * @return Object of the preparedStatement proxy
106: * @throws Exception if an error occurs
107: */
108: public static Object createSQLWrapper(Object pConn, MCInfo pMci,
109: SQLManager pConman, Logger pTrace) throws Exception {
110: Class class1 = pConn.getClass();
111: Class[] aclass = buildInterfaces(class1);
112: return Proxy.newProxyInstance(class1.getClassLoader(), aclass,
113: new JonasSQLWrapper(pConn, pMci, pConman, pTrace));
114: }
115:
116: /**
117: * Invoke call on the proxy
118: *
119: * @param obj the proxy instance that the method was invoked on
120: * @param method the Method instance
121: * @param aobj an array of objects containing the values of the arguments
122: * @throws Throwable if an error occurs
123: * @return Object the returned from the method invocation on the proxy instance
124: */
125: public Object invoke(Object obj, Method method, Object[] aobj)
126: throws Throwable {
127:
128: Object retObj = null;
129: if (method.getName().compareTo("prepareStatement") == 0) {
130: retObj = prepareStatement(method.getParameterTypes(), aobj);
131: if (retObj == null) {
132: retObj = method.invoke(connection, aobj);
133: }
134: } else {
135: if (method.getName().compareTo("close") == 0) {
136: invalid = true;
137: } else if (method.getName().compareTo("toString") == 0) {
138: return connection.toString();
139: } else if (method.getName().compareTo("commit") == 0) {
140: if (trace.isLoggable(BasicLevel.DEBUG)) {
141: trace.log(BasicLevel.DEBUG, "" + this );
142: }
143: } else {
144: checkIfValid();
145: }
146: retObj = method.invoke(connection, aobj);
147: }
148: return retObj;
149: }
150:
151: /**
152: * Invoke correct preparedStatement
153: * @param pTypes Class [] of parameter types
154: * @param pValues Class [] of parameter values
155: * @return Object the result of invoking the preparedStatement
156: * @throws Exception if any Exception occurs
157: */
158: public Object prepareStatement(Class[] pTypes, Object[] pValues)
159: throws Exception {
160:
161: checkIfValid();
162:
163: if (supportsPreparedCache) {
164: try {
165: Class[] mTypes = new Class[PROXY_FIXED_ARGS
166: + pTypes.length];
167: Object[] mValues = new Object[PROXY_FIXED_ARGS
168: + pValues.length];
169:
170: mTypes[0] = MCInfo.class;
171: mTypes[1] = Object.class;
172: mTypes[2] = String.class;
173:
174: mValues[0] = mci;
175: mValues[1] = connection;
176: mValues[2] = user;
177:
178: // Loop should be faster than System.arraycopy for small
179: // number of parameters
180: for (int i = 0; i < pTypes.length; i++) {
181: mTypes[PROXY_FIXED_ARGS + i] = pTypes[i];
182: mValues[PROXY_FIXED_ARGS + i] = pValues[i];
183: }
184:
185: Method meth1 = conman.getClass().getMethod(
186: "getPStatement", mTypes);
187: return meth1.invoke(conman, mValues);
188: } catch (Exception ex) {
189: ex.printStackTrace();
190: return null;
191: }
192: } else {
193: return null;
194: }
195:
196: }
197:
198: /*
199: // JDK 1.4
200: public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
201: throws SQLException {
202: checkIfValid();
203: if (supportsPreparedCache) {
204: return conman.getStatement(user, connection, sql, autoGeneratedKeys);
205: } else {
206: return con.prepareStatement(sql, autoGeneratedKeys);
207: }
208: }
209:
210: // JDK 1.4
211: public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
212: throws SQLException {
213: checkIfValid();
214: if (supportsPreparedCache) {
215: return conman.getStatement(user, connection, sql, columnIndexes);
216: } else {
217: return con.prepareStatement(sql, columnIndexes);
218: }
219: }
220:
221: // JDK 1.4
222: public PreparedStatement prepareStatement(String sql, int resultSetType,
223: int resultSetConcurrency,
224: int resultSetHoldability)
225: throws SQLException {
226: checkIfValid();
227: if (supportsPreparedCache) {
228: return conman.getStatement(user, connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
229: } else {
230: return con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
231: }
232: }
233:
234: // JDK 1.4
235: public PreparedStatement prepareStatement(String sql, String[] columnNames)
236: throws SQLException {
237: checkIfValid();
238: if (supportsPreparedCache) {
239: return conman.getStatement(user, connection, sql, columnNames);
240: } else {
241: return con.prepareStatement(sql, columnNames);
242: }
243: }
244: */
245:
246: /**
247: * Return a string describing this object
248: * @return String representing this object
249: */
250: public String toString() {
251: return connection.toString();
252: }
253:
254: /**
255: * Check if the wrapper is valid
256: * @throws SQLException if the wrapper is invalid
257: */
258: private void checkIfValid() throws SQLException {
259: if (invalid) {
260: throw new SQLException("Connection is closed");
261: }
262: }
263:
264: /* Utility methods to build interfaces*/
265: /**
266: * Build the class interfaces from the class object
267: * @param class1 Class to retrieve the interfaces
268: * @return Class [] all interfaces
269: */
270: private static Class[] buildInterfaces(Class class1) {
271: ArrayList arlist = new ArrayList();
272: addToList(class1, arlist);
273: Class[] aclass = new Class[arlist.size()];
274: return (Class[]) arlist.toArray(aclass);
275: }
276:
277: /**
278: * Add each of the interfaces
279: * @param cls Class to determine what interfaces are implemented
280: * @param lst List of interfaces
281: */
282: private static void addToList(Class cls, List lst) {
283: Class[] aclass = cls.getInterfaces();
284: for (int i = 0; i < aclass.length; i++) {
285: if (!lst.contains(aclass[i])) {
286: lst.add(aclass[i]);
287: }
288: addToList(aclass[i], lst);
289: }
290:
291: Class class2 = cls.getSuperclass();
292: if (class2 != null) {
293: addToList(class2, lst);
294: }
295: }
296: }
|