001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software 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 software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.test.jca.ejb;
023:
024: import java.rmi.RemoteException;
025: import java.sql.CallableStatement;
026: import java.sql.Connection;
027: import java.sql.PreparedStatement;
028: import java.sql.ResultSet;
029: import java.sql.SQLException;
030: import java.sql.Statement;
031:
032: import javax.ejb.CreateException;
033: import javax.ejb.DuplicateKeyException;
034: import javax.ejb.EJBException;
035: import javax.ejb.EntityBean;
036: import javax.ejb.EntityContext;
037: import javax.ejb.FinderException;
038: import javax.ejb.NoSuchEntityException;
039: import javax.ejb.ObjectNotFoundException;
040: import javax.naming.InitialContext;
041: import javax.naming.NamingException;
042: import javax.sql.DataSource;
043:
044: import org.jboss.ejb.plugins.cmp.jdbc.WrappedStatement;
045: import org.jboss.logging.Logger;
046:
047: /** A BMP bean which exercises the prepared statement cache.
048: *
049: * @author Scott.Stark@jboss.org
050: * @author Adrian.Brock@jboss.org
051: * @version $Revision: 57211 $
052: */
053: public class PreparedStatementBean implements EntityBean {
054: /** The serialVersionUID */
055: private static final long serialVersionUID = 6204314647869034863L;
056: static Logger log = Logger.getLogger(PreparedStatementBean.class);
057: private EntityContext ctx = null;
058: private DataSource ds;
059: private String key;
060: private String name;
061:
062: public void ejbActivate() {
063: }
064:
065: public void ejbPassivate() {
066: }
067:
068: public void ejbLoad() {
069: key = (String) ctx.getPrimaryKey();
070: log.debug("ejbLoad(" + key + ")");
071: try {
072: Connection con = ds.getConnection();
073: try {
074: PreparedStatement ps = con
075: .prepareStatement("SELECT name FROM BMPTABLE WHERE pk=?");
076: try {
077: ps.setString(1, key);
078: ResultSet rs = ps.executeQuery();
079:
080: if (rs.next() == false)
081: throw new NoSuchEntityException("Instance "
082: + key + " not found in database.");
083: name = rs.getString(1);
084: rs.close();
085: } finally {
086: ps.close();
087: }
088: } finally {
089: con.close();
090: }
091: } catch (SQLException e) {
092: throw new EJBException(e);
093: }
094: }
095:
096: public void ejbStore() {
097: log.debug("ejbStore(" + key + ")");
098: try {
099: Connection con = ds.getConnection();
100: try {
101: PreparedStatement ps = con
102: .prepareStatement("UPDATE BMPTABLE SET name=? WHERE pk=?");
103: try {
104: ps.setString(1, key);
105: ps.setString(2, name);
106: ps.executeUpdate();
107: } finally {
108: ps.close();
109: }
110: } finally {
111: con.close();
112: }
113: } catch (SQLException e) {
114: throw new EJBException(e);
115: }
116: }
117:
118: public void ejbRemove() {
119: log.debug("ejbRemove(" + key + ") called");
120: try {
121: Connection con = ds.getConnection();
122: try {
123: PreparedStatement ps = con
124: .prepareStatement("DELETE FROM BMPTABLE WHERE pk=?");
125: try {
126: ps.setString(1, key);
127: ps.executeUpdate();
128: } finally {
129: ps.close();
130: }
131: } finally {
132: con.close();
133: }
134: } catch (SQLException e) {
135: throw new EJBException(e);
136: }
137:
138: log.debug("Removed " + key);
139: }
140:
141: public void setEntityContext(EntityContext ctx) {
142: log.debug("setEntityContext() called");
143: this .ctx = ctx;
144: try {
145: InitialContext ic = new InitialContext();
146: ds = (DataSource) ic
147: .lookup("java:comp/env/jdbc/DataSource");
148: } catch (NamingException e) {
149: throw new EJBException("DataSource init failed", e);
150: }
151: }
152:
153: public void unsetEntityContext() throws EJBException,
154: RemoteException {
155: ds = null;
156:
157: }
158:
159: public String ejbCreate(String pk, String name)
160: throws CreateException, DuplicateKeyException {
161: log.debug("entry ejbCreate(" + pk + ", " + name + ")");
162: ensureTableExists();
163: try {
164: Connection con = ds.getConnection();
165: try {
166: PreparedStatement ps = con
167: .prepareStatement("INSERT INTO BMPTABLE VALUES (?,?)");
168: try {
169: ps.setString(1, pk);
170: ps.setString(2, name);
171: ps.execute();
172: } finally {
173: ps.close();
174: }
175: } finally {
176: con.close();
177: }
178: } catch (SQLException e) {
179: log.debug("failed", e);
180:
181: throw new CreateException("Entity bean creation failure: "
182: + e.getMessage());
183: }
184:
185: this .key = pk;
186: this .name = name;
187: log.debug("Created BMP: " + pk);
188: return pk;
189: }
190:
191: public void ejbPostCreate(String pk, String name) {
192: log.debug("entry ejbCreate(" + pk + ", " + name + ")");
193: }
194:
195: public String ejbFindByPrimaryKey(String pk) throws FinderException {
196: log.debug("ejbFindByPrimaryKey, pk=" + pk);
197: ensureTableExists();
198: try {
199: Connection con = ds.getConnection();
200: try {
201: PreparedStatement ps;
202:
203: ps = con
204: .prepareStatement("SELECT pk FROM BMPTABLE WHERE pk=?");
205: try {
206: ps.setString(1, pk);
207: ResultSet rs = ps.executeQuery();
208: if (!rs.next())
209: throw new ObjectNotFoundException(
210: "No bean with " + "pk=" + pk
211: + " found.");
212: rs.close();
213: return pk;
214: } finally {
215: ps.close();
216: }
217: } finally {
218: con.close();
219: }
220: } catch (SQLException e) {
221: throw new FinderException("Could not find pk=" + pk
222: + ", msg=" + e.getMessage());
223: }
224: }
225:
226: public long hashEntityTable() throws RemoteException {
227: long hash = 0;
228: try {
229: Connection con = ds.getConnection();
230: try {
231: PreparedStatement ps = con
232: .prepareStatement("SELECT pk FROM BMPTABLE");
233: try {
234: ResultSet rs = ps.executeQuery();
235: while (rs.next()) {
236: String pk = rs.getString(1);
237: PreparedStatement ps2 = con
238: .prepareStatement("SELECT name FROM BMPTABLE WHERE pk=?");
239: ps2.setString(1, pk);
240: ResultSet rs2 = ps2.executeQuery();
241: if (rs2.next()) {
242: String pkName = rs2.getString(1);
243: hash += pkName.hashCode();
244: }
245: rs2.close();
246: ps2.close();
247: }
248: rs.close();
249: } finally {
250: ps.close();
251: }
252: } finally {
253: con.close();
254: }
255: } catch (SQLException e) {
256: throw new RemoteException("Failed to calculate hash", e);
257: }
258: return hash;
259: }
260:
261: public void testPreparedStatementCache() throws RemoteException {
262: try {
263: Connection con = ds.getConnection();
264: try {
265: PreparedStatement ps = con
266: .prepareStatement("SELECT pk FROM BMPTABLE");
267: Statement ps1 = getWrappedStatement(ps);
268: ps.close();
269: ps = con.prepareStatement("SELECT pk FROM BMPTABLE");
270: Statement ps2 = getWrappedStatement(ps);
271: if (ps1 != ps2)
272: throw new EJBException("Statement " + ps1
273: + " was not cached: got " + ps2);
274: ps.close();
275: ps = con.prepareStatement("SELECT pk FROM BMPTABLE",
276: ResultSet.TYPE_FORWARD_ONLY,
277: ResultSet.CONCUR_READ_ONLY);
278: ps2 = getWrappedStatement(ps);
279: if (ps1 != ps2)
280: throw new EJBException(
281: "Statement "
282: + ps1
283: + " was not cached against default result set parameters: got "
284: + ps2);
285: ps.close();
286: ps = con.prepareStatement("SELECT pk FROM BMPTABLE",
287: ResultSet.TYPE_FORWARD_ONLY,
288: ResultSet.CONCUR_UPDATABLE);
289: ps2 = getWrappedStatement(ps);
290: if (ps1 == ps2)
291: throw new EJBException(
292: "Statement "
293: + ps1
294: + " should be different with different result set parameters: got "
295: + ps2);
296: ps.close();
297: } finally {
298: con.close();
299: }
300: } catch (SQLException e) {
301: throw new RemoteException("Unexpected sql exception", e);
302: }
303: }
304:
305: public void testPreparedStatementCacheDoubleClose()
306: throws RemoteException {
307: try {
308: Connection con = ds.getConnection();
309: try {
310: PreparedStatement ps = con
311: .prepareStatement("SELECT pk FROM BMPTABLE");
312: ps.close();
313: try {
314: ps.close();
315: } catch (SQLException e) {
316: log.debug("Got expected double close exception", e);
317: }
318: } finally {
319: con.close();
320: }
321: } catch (SQLException e) {
322: throw new RemoteException("Unexpected sql exception", e);
323: }
324: }
325:
326: public void testCallableStatementCache(String name)
327: throws RemoteException {
328: try {
329: InitialContext ctx = new InitialContext();
330: String query = (String) ctx.lookup("java:comp/env/" + name);
331:
332: Connection con = ds.getConnection();
333: try {
334: CallableStatement ps = con.prepareCall(query);
335: Statement ps1 = getWrappedStatement(ps);
336: ps.close();
337: ps = con.prepareCall(query);
338: Statement ps2 = getWrappedStatement(ps);
339: if (ps1 != ps2)
340: throw new EJBException("Statement " + ps1
341: + " was not cached: got " + ps2);
342: ps.close();
343: ps = con.prepareCall(query,
344: ResultSet.TYPE_FORWARD_ONLY,
345: ResultSet.CONCUR_READ_ONLY);
346: ps2 = getWrappedStatement(ps);
347: if (ps1 != ps2)
348: throw new EJBException(
349: "Statement "
350: + ps1
351: + " was not cached against default result set parameters: got "
352: + ps2);
353: ps.close();
354: ps = con.prepareCall(query,
355: ResultSet.TYPE_FORWARD_ONLY,
356: ResultSet.CONCUR_UPDATABLE);
357: ps2 = getWrappedStatement(ps);
358: if (ps1 == ps2)
359: throw new EJBException(
360: "Statement "
361: + ps1
362: + " should be different with different result set parameters: got "
363: + ps2);
364: ps.close();
365: } finally {
366: con.close();
367: }
368: } catch (SQLException e) {
369: throw new RemoteException("Unexpected sql exception", e);
370: } catch (NamingException e) {
371: throw new RemoteException("Failed to lookup query", e);
372: }
373: }
374:
375: public void testCallableStatementCacheDoubleClose(String name)
376: throws RemoteException {
377: try {
378: InitialContext ctx = new InitialContext();
379: String query = (String) ctx.lookup("java:comp/env/" + name);
380:
381: Connection con = ds.getConnection();
382: try {
383: CallableStatement ps = con.prepareCall(query);
384: ps.close();
385: try {
386: ps.close();
387: } catch (SQLException e) {
388: log.debug("Got expected double close exception", e);
389: }
390: } finally {
391: con.close();
392: }
393: } catch (SQLException e) {
394: throw new RemoteException("Unexpected sql exception", e);
395: } catch (NamingException e) {
396: throw new RemoteException("Failed to lookup query", e);
397: }
398: }
399:
400: public String executeStoredProc(String name) throws RemoteException {
401: String value = null;
402: try {
403: InitialContext ctx = new InitialContext();
404: String query = (String) ctx.lookup("java:comp/env/" + name);
405:
406: Connection con = ds.getConnection();
407: try {
408: CallableStatement ps = con.prepareCall(query);
409: try {
410: ResultSet rs = ps.executeQuery();
411: while (rs.next()) {
412: value = rs.getString(1);
413: }
414: rs.close();
415: } finally {
416: ps.close();
417: }
418: } finally {
419: con.close();
420: }
421: } catch (SQLException e) {
422: throw new RemoteException(
423: "Failed to execuate CallableStatement", e);
424: } catch (NamingException e) {
425: throw new RemoteException("Failed to lookup query", e);
426: }
427: return value;
428: }
429:
430: private void ensureTableExists() {
431: boolean exists = true;
432:
433: try {
434: Connection con = ds.getConnection();
435: try {
436: Statement s = con.createStatement();
437: try {
438: ResultSet rs = s
439: .executeQuery("SELECT * FROM BMPTABLE");
440: rs.close();
441: } finally {
442: s.close();
443: }
444: } finally {
445: con.close();
446: }
447: } catch (SQLException e) {
448: exists = false;
449: }
450:
451: if (!exists) {
452: try {
453: Connection con = ds.getConnection();
454: try {
455: Statement s = con.createStatement();
456: try {
457: s
458: .executeUpdate("CREATE TABLE BMPTABLE (pk VARCHAR(16), name VARCHAR(32))");
459: } finally {
460: s.close();
461: }
462: } finally {
463: con.close();
464: }
465: } catch (SQLException e) {
466: throw new EJBException(e);
467: }
468: }
469: }
470:
471: public Statement getWrappedStatement(Statement s)
472: throws SQLException {
473: while (s instanceof WrappedStatement)
474: s = ((WrappedStatement) s).getUnderlyingStatement();
475: return s;
476: }
477:
478: }
|