001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library 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 GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: JEntitySwitchCRC.java 9805 2006-10-27 08:28:32Z durieuxp $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.container;
025:
026: import javax.ejb.EJBException;
027: import javax.ejb.NoSuchObjectLocalException;
028: import javax.ejb.TransactionRolledbackLocalException;
029: import javax.transaction.Status;
030: import javax.transaction.SystemException;
031: import javax.transaction.Transaction;
032:
033: import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
034:
035: import org.objectweb.util.monolog.api.BasicLevel;
036:
037: /**
038: * Container read committed lock policy.
039: * transactions are serialized by the container.
040: * Accesses outside transaction read committed state.
041: * @author Philippe Durieux
042: */
043: public class JEntitySwitchCRC extends JEntitySwitch {
044:
045: /**
046: * EntityContext for transacted requests
047: */
048: protected JEntityContext itContext = null;
049:
050: /**
051: * EntityContext for non-transacted requests
052: */
053: protected JEntityContext ihContext = null;
054:
055: /**
056: * empty constructor. Object is initialized via init() because it is
057: * implemented differently according to jorm mappers.
058: */
059: public JEntitySwitchCRC() {
060: lockpolicy = EntityDesc.LOCK_CONTAINER_READ_COMMITTED;
061: }
062:
063: protected void initpolicy(JEntityFactory bf) {
064: lazyregister = false;
065: }
066:
067: protected JEntityContext getContext4Tx(Transaction tx) {
068: JEntityContext ctx = null;
069: if (tx == null) {
070: ctx = ihContext;
071: } else {
072: ctx = itContext;
073: }
074: return ctx;
075: }
076:
077: /**
078: * @param tx The Transaction
079: * @param the JEntityContext used for this tx
080: */
081: protected void setContext4Tx(Transaction tx, JEntityContext ctx) {
082: if (tx == null) {
083: ihContext = ctx;
084: } else {
085: itContext = ctx;
086: }
087: }
088:
089: /**
090: *
091: */
092: protected void removeContext4Tx(Transaction tx) {
093: // free this Context
094: if (tx == null) {
095: ihContext = null;
096: } else {
097: itContext = null;
098: }
099: }
100:
101: public void waitmyturn(Transaction tx) {
102:
103: // Synchronization.
104: if (tx != null) {
105: // Must wait in case of TX or if instance has been modified outside
106: // transaction.
107: // Don't wait transactions if 1 instance per transaction.
108: int waitcount = 0;
109: Transaction lastrunning = null;
110: while (runningtx != null && !tx.equals(runningtx)) {
111: if (TraceEjb.isDebugSynchro()) {
112: TraceEjb.synchro.log(BasicLevel.DEBUG, ident
113: + "mapICtx IT: WAIT end IT");
114: }
115: // deadlock detection
116: blockedtx.add(tx);
117: if (waitcount > 0 && runningtx.equals(lastrunning)
118: && bf.isDeadLocked(runningtx)) {
119: blockedtx.remove(tx);
120: try {
121: tx.setRollbackOnly();
122: } catch (SystemException e) {
123: TraceEjb.logger
124: .log(
125: BasicLevel.ERROR,
126: ident
127: + "getICtx IT: unexpected exception setting rollbackonly",
128: e);
129: }
130: TraceEjb.logger.log(BasicLevel.WARN, ident
131: + "getICtx IT: transaction rolled back");
132: throw new TransactionRolledbackLocalException(
133: "possible deadlock");
134: }
135: lastrunning = runningtx;
136: waitcount++;
137: waiters++;
138: try {
139: wait(deadlockTimeout);
140: if (TraceEjb.isDebugSynchro()) {
141: TraceEjb.synchro.log(BasicLevel.DEBUG, ident
142: + "mapICtx IT: NOTIFIED");
143: }
144: } catch (InterruptedException e) {
145: if (TraceEjb.isDebugSynchro()) {
146: TraceEjb.synchro.log(BasicLevel.DEBUG, ident
147: + "mapICtx IT: INTERRUPTED", e);
148: }
149: } catch (Exception e) {
150: throw new EJBException(
151: "JEntitySwitch synchronization pb", e);
152: } finally {
153: waiters--;
154: blockedtx.remove(tx);
155: }
156: // If transaction has been rolledback or set rollback only, give up.
157: int status = Status.STATUS_ROLLEDBACK;
158: try {
159: status = tx.getStatus();
160: } catch (SystemException e) {
161: TraceEjb.logger
162: .log(
163: BasicLevel.ERROR,
164: ident
165: + "getICtx IT: unexpected exception getting transaction status",
166: e);
167: }
168: switch (status) {
169: case Status.STATUS_MARKED_ROLLBACK:
170: case Status.STATUS_ROLLEDBACK:
171: case Status.STATUS_ROLLING_BACK:
172: if (TraceEjb.isVerbose()) {
173: TraceEjb.logger
174: .log(
175: BasicLevel.WARN,
176: ident
177: + "getICtx IT: transaction rolled back");
178: }
179: throw new TransactionRolledbackLocalException(
180: "rollback occured while waiting");
181: }
182: }
183: }
184: }
185:
186: /**
187: * try to passivate instances
188: * @param store not used for this policy
189: * @param passivate always true for this policy
190: * @return result of operation: (not really used here)
191: * ALL_DONE = instances passivated
192: * NOT_DONE = not all passivated
193: */
194: public synchronized int passivateIH(boolean store, boolean passivate) {
195:
196: long ttd = estimestamp - System.currentTimeMillis();
197: if (ttd > 0) {
198: TraceEjb.context.log(BasicLevel.DEBUG, "too recent");
199: return NOT_DONE;
200: }
201:
202: int icount = 0;
203:
204: // Instance used when no transaction.
205: JEntityContext jec = ihContext;
206: if (jec != null && countIH == 0) {
207: if (TraceEjb.isDebugContext()) {
208: TraceEjb.context.log(BasicLevel.DEBUG, "passivate: "
209: + jec);
210: }
211: if (jec.passivate()) {
212: // Will be pooled only if min-pool-size not reached in free list.
213: bf.releaseJContext(jec, 1);
214: ihContext = null;
215: icount++;
216: }
217: }
218:
219: // Instance used for transactions
220: jec = itContext;
221: if (jec != null && runningtx == null && countIT == 0) {
222: if (TraceEjb.isDebugContext()) {
223: TraceEjb.context.log(BasicLevel.DEBUG, "passivated: "
224: + jec);
225: }
226: if (jec.passivate()) {
227: if (jec.getMyTx() != null) {
228: TraceEjb.context.log(BasicLevel.WARN,
229: "Will forget Tx???");
230: }
231: // Will be pooled only if min-pool-size not reached in free list.
232: bf.releaseJContext(jec, 1);
233: itContext = null;
234: icount++;
235: }
236: }
237:
238: // notify waiters for new instances
239: if (icount > 0 && waiters > 0) {
240: notifyAll();
241: }
242:
243: // all instances passivated
244: if (icount == 2) {
245: // look if we can destroy the objects
246: if (inactivityTimeout > 0) {
247: ttd = inactivityTimeout + estimestamp
248: - System.currentTimeMillis();
249: if (ttd <= 0) {
250: detachPk();
251: estimestamp = System.currentTimeMillis();
252: }
253: }
254: return ALL_DONE;
255: }
256: return NOT_DONE;
257: }
258:
259: public synchronized void endIH() {
260: TraceEjb.synchro.log(BasicLevel.ERROR, ident);
261: // Not used.
262: }
263:
264: /**
265: * @return State of this instance. State values are 0=in-tx, 1=out-tx, 2=idle,
266: * 3=passive, 4=removed. we don't synchronize this method to avoid
267: * jadmin blocks
268: */
269: public int getState() {
270: if (ihContext != null) {
271: if (ihContext.isMarkedRemoved()) {
272: return 4;
273: } else {
274: if (itContext == null) {
275: return 2;
276: }
277: }
278: }
279: if (itContext != null) {
280: if (itContext.isMarkedRemoved()) {
281: return 4;
282: } else {
283: if (runningtx != null) {
284: return 0;
285: } else {
286: return 2;
287: }
288: }
289: }
290: return 3;
291: }
292:
293: }
|