001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2004 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: SimpleApplicationDirectoryEJB.java,v 1.15 2007/01/31 21:26:48 mlipp Exp $
021: *
022: * $Log: SimpleApplicationDirectoryEJB.java,v $
023: * Revision 1.15 2007/01/31 21:26:48 mlipp
024: * Undid erroneous change.
025: *
026: * Revision 1.14 2007/01/31 12:24:07 drmlipp
027: * Design revisited.
028: *
029: * Revision 1.13 2006/12/12 10:54:38 drmlipp
030: * Added method for retrieving infos by application.
031: *
032: * Revision 1.11 2006/10/25 21:42:34 mlipp
033: * Handling duplicate keys.
034: *
035: * Revision 1.10 2006/10/25 15:46:04 drmlipp
036: * Added support for looking up entries by key.
037: *
038: * Revision 1.9 2006/10/11 09:05:54 drmlipp
039: * Fixed EJB naming.
040: *
041: * Revision 1.8 2006/10/07 20:41:34 mlipp
042: * Merged J2EE 1.4 adaptions from test branch.
043: *
044: * Revision 1.7 2006/09/29 12:32:09 drmlipp
045: * Consistently using WfMOpen as projct name now.
046: *
047: * Revision 1.6 2006/09/22 08:17:14 drmlipp
048: * Removed strange import.
049: *
050: * Revision 1.5 2006/09/21 12:20:38 drmlipp
051: * Added lookup by resource.
052: *
053: * Revision 1.4 2005/04/22 15:11:05 drmlipp
054: * Merged changes from 1.3 branch up to 1.3p15.
055: *
056: * Revision 1.2.6.2 2005/04/13 16:14:08 drmlipp
057: * Optimized db access.
058: *
059: * Revision 1.3 2005/04/08 11:28:05 drmlipp
060: * Merged changes from 1.3 branch up to 1.3p6.
061: *
062: * Revision 1.2.6.1 2005/04/04 20:09:22 drmlipp
063: * Changed WLS transaction isolation.
064: *
065: * Revision 1.2 2004/09/10 12:44:31 drmlipp
066: * Enabled call by reference for weblogic by default.
067: *
068: * Revision 1.1.1.1 2004/08/18 15:17:39 drmlipp
069: * Update to 1.2
070: *
071: * Revision 1.6 2004/07/04 17:36:03 lipp
072: * Added JOnAS support.
073: *
074: * Revision 1.5 2004/04/08 09:34:54 lipp
075: * Clarified documentation of package structure.
076: *
077: * Revision 1.4 2004/02/27 12:01:48 lipp
078: * Fixed permissions.
079: *
080: * Revision 1.3 2004/02/20 15:58:22 lipp
081: * Several WaitTool fixes.
082: *
083: * Revision 1.2 2004/02/19 18:06:42 lipp
084: * Fixed application name handling.
085: *
086: * Revision 1.1 2004/02/19 17:55:54 lipp
087: * Initial version of waittool.
088: *
089: */
090: package de.danet.an.workflow.tools.util;
091:
092: import java.io.IOException;
093:
094: import java.util.ArrayList;
095: import java.util.Collection;
096: import java.util.Date;
097: import java.util.Iterator;
098:
099: import java.sql.Connection;
100: import java.sql.ResultSet;
101: import java.sql.SQLException;
102: import java.sql.Timestamp;
103:
104: import javax.ejb.CreateException;
105: import javax.ejb.EJBException;
106: import javax.ejb.SessionBean;
107: import javax.ejb.SessionContext;
108: import javax.naming.NamingException;
109: import javax.sql.DataSource;
110:
111: import de.danet.an.util.EJBUtil;
112: import de.danet.an.util.JDBCUtil;
113: import de.danet.an.util.UniversalPrepStmt;
114:
115: import de.danet.an.workflow.omgcore.WfAssignment;
116:
117: import de.danet.an.workflow.api.Activity;
118: import de.danet.an.workflow.api.ActivityUniqueKey;
119: import de.danet.an.workflow.api.InvalidKeyException;
120:
121: /**
122: * This EJB provides a directory for simple applications. Applications
123: * are considered simple in this context if their state can
124: * efficiently be represented (and stored) using a single serializable
125: * object.<P>
126: *
127: * This directory maps a unique id to the activity unique key
128: * information of the executing activity and an associated state (and
129: * vice versa). Optionally, the assignment time and an assigned
130: * resource may be saved in this directory as well.
131: *
132: * @see de.danet.an.workflow.util
133: *
134: * @author <a href="mailto:lipp@danet.de">Michael Lipp</a>
135: * @version $Revision: 1.15 $
136: * @ejb.bean name="SimpleApplicationDirectory"
137: * jndi-name="ejb/@@@_JNDI_Name_Prefix_@@@SimpleApplicationDirectory"
138: * local-jndi-name="ejb/@@@_JNDI_Name_Prefix_@@@SimpleApplicationDirectoryLocal"
139: * display-name="Simple Application Directory EJB"
140: * type="Stateless" transaction-type="Container" view-type="both"
141: * @jonas.bean ejb-name="SimpleApplicationDirectory"
142: * @ejb.transaction type="Required"
143: * @ejb.permission role-name="WfMOpenAdmin"
144: * @ejb.ejb-external-ref ref-name="ejb/JdbcKeyGenLocal" link="KeyGen"
145: * type="Session" view-type="local" home="de.danet.an.util.KeyGenLocalHome"
146: * business="de.danet.an.util.KeyGenLocal"
147: * @ejb.resource-ref res-ref-name="jdbc/WfEngine"
148: * res-type="javax.sql.DataSource" res-auth="Container"
149: * @jonas.resource res-ref-name="jdbc/WfEngine" jndi-name="jdbc_1"
150: * @weblogic.enable-call-by-reference True
151: * @weblogic.resource-description
152: * res-ref-name="jdbc/WfEngine" jndi-name="DefaultDS"
153: * @weblogic.transaction-isolation TRANSACTION_READ_COMMITTED
154: */
155:
156: public class SimpleApplicationDirectoryEJB implements SessionBean {
157:
158: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
159: .getLog(SimpleApplicationDirectoryEJB.class);
160:
161: /**
162: * The SessionContext interface of the instance.
163: */
164: private SessionContext ctx;
165:
166: /**
167: * The data source of the database.
168: * @see javax.sql.DataSource
169: */
170: private DataSource ds = null;
171:
172: /** Database name. */
173: private static final String DB_NAME = "java:comp/env/jdbc/WfEngine";
174:
175: /**
176: * Creates an instance of <code>SimpleApplicationDirectoryEJB</code>
177: * with all attributes initialized to default values.
178: */
179: public SimpleApplicationDirectoryEJB() {
180: }
181:
182: /**
183: * Save the session context asigned by the container.
184: * @param context the context
185: */
186: public void setSessionContext(SessionContext context) {
187: ctx = context;
188: // getting new data source
189: try {
190: ds = JDBCUtil.refreshDS(null, DB_NAME);
191: } catch (NamingException ne) {
192: throw new EJBException(ne);
193: }
194: }
195:
196: /**
197: * Create a new EJB.
198: * @throws CreateException if creation fails
199: */
200: public void ejbCreate() throws CreateException {
201: }
202:
203: /**
204: * Remove this EJB.
205: */
206: public void ejbRemove() {
207: ds = null;
208: ctx = null;
209: }
210:
211: /**
212: * Not called for stateless session beans.
213: * @see javax.ejb.SessionBean
214: */
215: public void ejbActivate() throws EJBException {
216: }
217:
218: /**
219: * Not called for stateless session beans.
220: * @see javax.ejb.SessionBean
221: */
222: public void ejbPassivate() throws EJBException {
223: }
224:
225: /**
226: * Register a new application instance. This method returns a unique
227: * key that can be used to {@link #instanceInfo(long) retrieve},
228: * {@link #updateState(long, Object) update} and
229: * {@link #removeInstance(long)} remove the instance information.<P>
230: *
231: * @param applName the application name
232: * @param activity the invoking activity
233: * @param state the application state
234: * @param saveAssignment if <code>true</code> the assigned
235: * resource will be saved to allow searching application instances
236: * with a particular assignee
237: * @return the instance id
238: * @ejb.interface-method view-type="both"
239: */
240: public long registerInstance(String applName, Activity activity,
241: Object state, boolean saveAssignment) {
242: return registerInstance(applName, null, activity, state,
243: saveAssignment);
244: }
245:
246: /**
247: * Register a new application instance. This method returns a unique
248: * key that may be used to
249: *
250: * @param applName the application name
251: * @param applInstKey an arbitrary key for this instance, up to 1000
252: * characters long
253: * @param activity the invoking activity
254: * @param state the application state
255: * @param saveAssignment if <code>true</code> the assigned
256: * resource will be saved to allow searching application instances
257: * with a particular assignee
258: * @return the instance id
259: * @ejb.interface-method view-type="both"
260: */
261: public long registerInstance(String applName, String applInstKey,
262: Activity activity, Object state, boolean saveAssignment) {
263: try {
264: Connection con = null;
265: UniversalPrepStmt prepStmt = null;
266: try {
267: ActivityUniqueKey auk = activity.uniqueKey();
268: con = ds.getConnection();
269: long instId = EJBUtil
270: .newPrimaryKey("SimpleApplicationDirectory");
271: prepStmt = new UniversalPrepStmt(
272: ds,
273: con,
274: "INSERT INTO SimpleAppl (DBId, ApplName, "
275: + "InstKey, ActivityKey, ProcessKey, ProcessMgr"
276: + (saveAssignment ? ", ResourceKey"
277: : "")
278: + ", AssignedAt, InstData) VALUES (?, ?, ?, ?, ?, ?"
279: + (saveAssignment ? ", ?" : "")
280: + ", ?, ?)");
281: int offset = 1;
282: prepStmt.setLong(offset++, instId);
283: prepStmt.setString(offset++, applName);
284: prepStmt.setString(offset++, applInstKey);
285: prepStmt.setString(offset++, auk.activityKey());
286: prepStmt.setString(offset++, auk.processKey());
287: prepStmt.setString(offset++, auk.managerName());
288: if (saveAssignment) {
289: String resourceKey = null;
290: Iterator i = activity.assignments().iterator();
291: if (i.hasNext()) {
292: WfAssignment assignment = (WfAssignment) i
293: .next();
294: resourceKey = assignment.assignee()
295: .resourceKey();
296: }
297: prepStmt.setString(offset++, resourceKey);
298: }
299: prepStmt.setTimestamp(offset++, new Timestamp(System
300: .currentTimeMillis()));
301: prepStmt.setBinary(offset++, state);
302: prepStmt.executeUpdate();
303: if (logger.isDebugEnabled()) {
304: logger.debug("Created application " + instId
305: + " for " + auk);
306: }
307: return instId;
308: } finally {
309: JDBCUtil.closeAll(null, prepStmt, con);
310: }
311: } catch (SQLException e) {
312: throw new EJBException(e);
313: } catch (IOException e) {
314: throw new EJBException(e);
315: }
316: }
317:
318: /**
319: * Remove an application instance.
320: *
321: * @param instId the application instance id previously assigned
322: * by {@link #registerInstance <code>registerInstance</code>}
323: * @ejb.interface-method view-type="both"
324: */
325: public void removeInstance(long instId) {
326: try {
327: Connection con = null;
328: UniversalPrepStmt prepStmt = null;
329: try {
330: con = ds.getConnection();
331: prepStmt = new UniversalPrepStmt(ds, con,
332: "DELETE FROM SimpleAppl WHERE DBId = ?");
333: prepStmt.setLong(1, instId);
334: prepStmt.executeUpdate();
335: if (logger.isDebugEnabled()) {
336: logger.debug("Removed application " + instId);
337: }
338: } finally {
339: JDBCUtil.closeAll(null, prepStmt, con);
340: }
341: } catch (SQLException e) {
342: throw new EJBException(e);
343: }
344: }
345:
346: /**
347: * Return the information associated with the application instance.
348: *
349: * @param instId the application instance id previously assigned
350: * by {@link #registerInstance <code>registerInstance</code>}
351: * @throws InvalidKeyException if there is no data available for
352: * the given id
353: * @return the info
354: * @ejb.interface-method view-type="both"
355: */
356: public SimpleApplicationInfo instanceInfo(long instId)
357: throws InvalidKeyException {
358: try {
359: Connection con = null;
360: UniversalPrepStmt prepStmt = null;
361: ResultSet rs = null;
362: try {
363: con = ds.getConnection();
364: prepStmt = new UniversalPrepStmt(ds, con,
365: "SELECT ActivityKey, ProcessKey, ProcessMgr, "
366: + "ResourceKey, AssignedAt, InstData "
367: + "FROM SimpleAppl WHERE DBId = ?");
368: prepStmt.setLong(1, instId);
369: rs = prepStmt.executeQuery();
370: if (!rs.next()) {
371: throw new InvalidKeyException(
372: "No application instance with key = "
373: + instId);
374: }
375: String actKey = rs.getString(1);
376: String prcKey = rs.getString(2);
377: String mgrKey = rs.getString(3);
378: String resKey = rs.getString(4);
379: Date asndAt = rs.getTimestamp(5);
380: Object state = JDBCUtil.getBinary(rs, 6);
381: return new SimpleApplicationInfo(instId,
382: actKey == null ? null : new ActivityUniqueKey(
383: mgrKey, prcKey, actKey), asndAt,
384: resKey, state);
385: } finally {
386: JDBCUtil.closeAll(rs, prepStmt, con);
387: }
388: } catch (ClassNotFoundException e) {
389: throw new EJBException(e);
390: } catch (IOException e) {
391: throw new EJBException(e);
392: } catch (SQLException e) {
393: throw new EJBException(e);
394: }
395: }
396:
397: /**
398: * Return the information associated with the activity.
399: *
400: * @param auk the unique key of the activity an application
401: * instance is expected to be registered for.
402: * @throws InvalidKeyException if there is no data available for
403: * the given activity
404: * @return the info
405: * @ejb.interface-method view-type="both"
406: */
407: public SimpleApplicationInfo infoByActivity(ActivityUniqueKey auk)
408: throws InvalidKeyException {
409: try {
410: Connection con = null;
411: UniversalPrepStmt prepStmt = null;
412: ResultSet rs = null;
413: try {
414: con = ds.getConnection();
415: prepStmt = new UniversalPrepStmt(
416: ds,
417: con,
418: "SELECT DBId, ResourceKey, AssignedAt, InstData "
419: + "FROM SimpleAppl WHERE ActivityKey = ? "
420: + "AND ProcessKey = ? AND ProcessMgr = ?");
421: prepStmt.setString(1, auk.activityKey());
422: prepStmt.setString(2, auk.processKey());
423: prepStmt.setString(3, auk.managerName());
424: rs = prepStmt.executeQuery();
425: if (!rs.next()) {
426: throw new InvalidKeyException(
427: "No application instance for activity = "
428: + auk);
429: }
430: long instId = rs.getLong(1);
431: String resKey = rs.getString(2);
432: Date asndAt = rs.getTimestamp(3);
433: Object state = JDBCUtil.getBinary(rs, 4);
434: return new SimpleApplicationInfo(instId, auk, asndAt,
435: resKey, state);
436: } finally {
437: JDBCUtil.closeAll(rs, prepStmt, con);
438: }
439: } catch (ClassNotFoundException e) {
440: throw new EJBException(e);
441: } catch (IOException e) {
442: throw new EJBException(e);
443: } catch (SQLException e) {
444: throw new EJBException(e);
445: }
446: }
447:
448: /**
449: * Return infos associated with a given application.
450: *
451: * @param applName the application name
452: * @return the infos as collection
453: * @ejb.interface-method view-type="both"
454: */
455: public Collection infosByApplication(String applName) {
456: Collection res = new ArrayList();
457: try {
458: Connection con = null;
459: UniversalPrepStmt prepStmt = null;
460: ResultSet rs = null;
461: try {
462: con = ds.getConnection();
463: prepStmt = new UniversalPrepStmt(
464: ds,
465: con,
466: "SELECT DBId, ActivityKey, ProcessKey, "
467: + "ProcessMgr, ResourceKey, AssignedAt, InstData "
468: + "FROM SimpleAppl WHERE ApplName = ? ");
469: prepStmt.setString(1, applName);
470: rs = prepStmt.executeQuery();
471: while (rs.next()) {
472: int pos = 1;
473: long instId = rs.getLong(pos++);
474: String actKey = rs.getString(pos++);
475: String procKey = rs.getString(pos++);
476: String procMgr = rs.getString(pos++);
477: String resourceKey = rs.getString(pos++);
478: Date asndAt = rs.getTimestamp(pos++);
479: Object state = JDBCUtil.getBinary(rs, pos++);
480: ActivityUniqueKey auk = new ActivityUniqueKey(
481: procMgr, procKey, actKey);
482: res.add(new SimpleApplicationInfo(instId, auk,
483: asndAt, resourceKey, state));
484: }
485: return res;
486: } finally {
487: JDBCUtil.closeAll(rs, prepStmt, con);
488: }
489: } catch (ClassNotFoundException e) {
490: throw new EJBException(e);
491: } catch (IOException e) {
492: throw new EJBException(e);
493: } catch (SQLException e) {
494: throw new EJBException(e);
495: }
496: }
497:
498: /**
499: * Return the infos associated with the given application name and key.
500: *
501: * @param applName the application name
502: * @param applInstKey the key associated with the instance
503: * @return the infos or an empty collection if no infos
504: * with the given application name and key exist
505: * @ejb.interface-method view-type="both"
506: */
507: public Collection infosByKey(String applName, String applInstKey)
508: throws InvalidKeyException {
509: try {
510: Collection res = new ArrayList();
511: Connection con = null;
512: UniversalPrepStmt prepStmt = null;
513: ResultSet rs = null;
514: try {
515: con = ds.getConnection();
516: prepStmt = new UniversalPrepStmt(
517: ds,
518: con,
519: "SELECT DBId, ActivityKey, ProcessKey, "
520: + "ProcessMgr, ResourceKey, AssignedAt, InstData "
521: + "FROM SimpleAppl WHERE ApplName = ? AND InstKey = ?");
522: prepStmt.setString(1, applName);
523: prepStmt.setString(2, applInstKey);
524: rs = prepStmt.executeQuery();
525: while (rs.next()) {
526: int pos = 1;
527: long instId = rs.getLong(pos++);
528: String actKey = rs.getString(pos++);
529: String procKey = rs.getString(pos++);
530: String procMgr = rs.getString(pos++);
531: String resKey = rs.getString(pos++);
532: Date asndAt = rs.getTimestamp(pos++);
533: Object state = JDBCUtil.getBinary(rs, pos++);
534: ActivityUniqueKey auk = new ActivityUniqueKey(
535: procMgr, procKey, actKey);
536: res.add(new SimpleApplicationInfo(instId, auk,
537: asndAt, resKey, state));
538: }
539: return res;
540: } finally {
541: JDBCUtil.closeAll(rs, prepStmt, con);
542: }
543: } catch (ClassNotFoundException e) {
544: throw new EJBException(e);
545: } catch (IOException e) {
546: throw new EJBException(e);
547: } catch (SQLException e) {
548: throw new EJBException(e);
549: }
550: }
551:
552: /**
553: * Return infos associated with a given application and resource.
554: *
555: * @param applName the application name
556: * @param resourceKey the resource's key
557: * @return the infos as collection
558: * @ejb.interface-method view-type="both"
559: */
560: public Collection infosByResource(String applName,
561: String resourceKey) {
562: Collection res = new ArrayList();
563: try {
564: Connection con = null;
565: UniversalPrepStmt prepStmt = null;
566: ResultSet rs = null;
567: try {
568: con = ds.getConnection();
569: prepStmt = new UniversalPrepStmt(
570: ds,
571: con,
572: "SELECT DBId, ActivityKey, ProcessKey, "
573: + "ProcessMgr, AssignedAt, InstData "
574: + "FROM SimpleAppl "
575: + "WHERE ApplName = ? AND ResourceKey = ? ");
576: prepStmt.setString(1, applName);
577: prepStmt.setString(2, resourceKey);
578: rs = prepStmt.executeQuery();
579: while (rs.next()) {
580: int pos = 1;
581: long instId = rs.getLong(pos++);
582: String actKey = rs.getString(pos++);
583: String procKey = rs.getString(pos++);
584: String procMgr = rs.getString(pos++);
585: Date asndAt = rs.getTimestamp(pos++);
586: Object state = JDBCUtil.getBinary(rs, pos++);
587: ActivityUniqueKey auk = new ActivityUniqueKey(
588: procMgr, procKey, actKey);
589: res.add(new SimpleApplicationInfo(instId, auk,
590: asndAt, resourceKey, state));
591: }
592: return res;
593: } finally {
594: JDBCUtil.closeAll(rs, prepStmt, con);
595: }
596: } catch (ClassNotFoundException e) {
597: throw new EJBException(e);
598: } catch (IOException e) {
599: throw new EJBException(e);
600: } catch (SQLException e) {
601: throw new EJBException(e);
602: }
603: }
604:
605: /**
606: * Update the state information associated with the given
607: * application instance id.
608: *
609: * @param instId the application instance id previously assigned
610: * by {@link #registerInstance <code>registerInstance</code>}
611: * @param state the new state
612: * @throws InvalidKeyException if there is no application instance
613: * with the given id
614: * @ejb.interface-method view-type="both"
615: */
616: public void updateState(long instId, Object state)
617: throws InvalidKeyException {
618: try {
619: Connection con = null;
620: UniversalPrepStmt prepStmt = null;
621: ResultSet rs = null;
622: try {
623: con = ds.getConnection();
624: prepStmt = new UniversalPrepStmt(ds, con,
625: "UPDATE SimpleAppl SET InstData = ? WHERE DBId = ? ");
626: prepStmt.setBinary(1, state);
627: prepStmt.setLong(2, instId);
628: if (prepStmt.executeUpdate() == 0) {
629: throw new InvalidKeyException(
630: "No application instance with key = "
631: + instId);
632: }
633: if (logger.isDebugEnabled()) {
634: logger.debug("Updated state for application "
635: + instId);
636: }
637: } finally {
638: JDBCUtil.closeAll(rs, prepStmt, con);
639: }
640: } catch (IOException e) {
641: throw new EJBException(e);
642: } catch (SQLException e) {
643: throw new EJBException(e);
644: }
645: }
646:
647: /**
648: * Update the activity associated with the given application
649: * instance. This is useful if an application instance is started
650: * by one tool (agent) invocation and stopped by another.<P>
651: *
652: * Be careful to ensure the eventual termination of the
653: * application. If the creating activity has completed, the
654: * terminate method of the tool agent that started the application
655: * will not be called on abnormal process completion. So, if a
656: * process is terminated abnormally and the starting activity is
657: * closed and the stopping activity has not yet been started (and
658: * associated with the application) the application will not be
659: * stopped. This should normally not be a problem for simple
660: * applications.<P>
661: *
662: * As a convenience, any application information that is still
663: * registered after a process completion will automatically be
664: * deleted.<P>
665: *
666: * The new activity must belong to the same process as the
667: * activity that initially created the application instance.
668: *
669: * @param instId the application instance id previously assigned
670: * by {@link #registerInstance <code>registerInstance</code>}
671: * @param auk the new activity's unique key. May be
672: * <code>null</code> if the application instance is temporarily
673: * not associated with an activity.
674: * @throws InvalidKeyException if there is no application instance
675: * with the given id
676: * @ejb.interface-method view-type="both"
677: */
678: public void updateInvokingActivity(long instId,
679: ActivityUniqueKey auk) throws InvalidKeyException {
680: try {
681: Connection con = null;
682: UniversalPrepStmt prepStmt = null;
683: ResultSet rs = null;
684: try {
685: con = ds.getConnection();
686: prepStmt = new UniversalPrepStmt(ds, con,
687: "UPDATE SimpleAppl "
688: + "SET ActivityKey = ? WHERE DBId = ?");
689: prepStmt.setString(1, auk == null ? null : auk
690: .activityKey());
691: prepStmt.setLong(2, instId);
692: if (prepStmt.executeUpdate() == 0) {
693: throw new InvalidKeyException(
694: "No application instance with key = "
695: + instId);
696: }
697: if (logger.isDebugEnabled()) {
698: logger.debug("Application " + instId
699: + " has been associated with " + auk);
700: }
701: } finally {
702: JDBCUtil.closeAll(rs, prepStmt, con);
703: }
704: } catch (SQLException e) {
705: throw new EJBException(e);
706: }
707: }
708:
709: }
|