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.ejb;
023:
024: import java.io.Serializable;
025: import java.rmi.RemoteException;
026: import java.security.Principal;
027: import java.util.Collection;
028: import java.util.Date;
029:
030: import javax.ejb.EJBContext;
031: import javax.ejb.EJBException;
032: import javax.ejb.EJBHome;
033: import javax.ejb.EJBLocalHome;
034: import javax.ejb.EJBLocalObject;
035: import javax.ejb.EJBObject;
036: import javax.ejb.EntityBean;
037: import javax.ejb.EntityContext;
038: import javax.ejb.Timer;
039: import javax.ejb.TimerService;
040: import javax.transaction.UserTransaction;
041:
042: import org.jboss.ejb.plugins.lock.NonReentrantLock;
043:
044: /**
045: * The EntityEnterpriseContext is used to associate EntityBean instances
046: * with metadata about it.
047: *
048: * @see EnterpriseContext
049: *
050: * @author <a href="mailto:rickard.oberg@telkel.com">Rickard �berg</a>
051: * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
052: * @author <a href="mailto:docodan@mvcsoft.com">Daniel OConnor</a>
053: * @version $Revision: 57209 $
054: */
055: public class EntityEnterpriseContext extends EnterpriseContext {
056: private EJBObject ejbObject;
057: private EJBLocalObject ejbLocalObject;
058: private EntityContext ctx;
059:
060: /**
061: * True if this instance has been registered with the TM for transactional
062: * demarcation.
063: */
064: private boolean hasTxSynchronization = false;
065:
066: /**
067: * Specifies whether the instance is associated with a transaction and should be synchronized.
068: */
069: private GlobalTxEntityMap.TxAssociation txAssociation = GlobalTxEntityMap.NONE;
070:
071: /**
072: * True if this instances' state is valid when a bean is called the state
073: * is not synchronized with the DB but "valid" as long as the transaction
074: * runs.
075: */
076: private boolean valid = false;
077:
078: /**
079: * Is this context in a readonly invocation.
080: */
081: private boolean readOnly = false;
082:
083: /**
084: * The persistence manager may attach any metadata it wishes to this
085: * context here.
086: */
087: private Object persistenceCtx;
088:
089: /** The cacheKey for this context */
090: private Object key;
091:
092: private NonReentrantLock methodLock = new NonReentrantLock();
093:
094: /** used to force passivation after commit even if the co is not C */
095: private boolean passivateAfterCommit;
096:
097: public EntityEnterpriseContext(Object instance, Container con)
098: throws RemoteException {
099: super (instance, con);
100: ctx = new EntityContextImpl();
101: try {
102: AllowedOperationsAssociation
103: .pushInMethodFlag(IN_SET_ENTITY_CONTEXT);
104: ((EntityBean) instance).setEntityContext(ctx);
105: } finally {
106: AllowedOperationsAssociation.popInMethodFlag();
107: }
108: }
109:
110: /**
111: * A non-reentrant deadlock detectable lock that is used to protected against
112: * entity bean reentrancy.
113: * @return
114: */
115: public NonReentrantLock getMethodLock() {
116: return methodLock;
117: }
118:
119: public void clear() {
120: super .clear();
121:
122: hasTxSynchronization = false;
123: valid = false;
124: readOnly = false;
125: key = null;
126: persistenceCtx = null;
127: ejbObject = null;
128: ejbLocalObject = null;
129: txAssociation = GlobalTxEntityMap.NONE;
130: passivateAfterCommit = false;
131: }
132:
133: public void discard() throws RemoteException {
134: ((EntityBean) instance).unsetEntityContext();
135: }
136:
137: public EJBContext getEJBContext() {
138: return ctx;
139: }
140:
141: public void setEJBObject(EJBObject eo) {
142: ejbObject = eo;
143: }
144:
145: public EJBObject getEJBObject() {
146: // Context can have no EJBObject (created by finds) in which case
147: // we need to wire it at call time
148: if (ejbObject == null && con.getProxyFactory() != null) {
149: ejbObject = (EJBObject) con.getProxyFactory()
150: .getEntityEJBObject(id);
151: }
152: return ejbObject;
153: }
154:
155: public void setEJBLocalObject(EJBLocalObject eo) {
156: ejbLocalObject = eo;
157: }
158:
159: public EJBLocalObject getEJBLocalObject() {
160: if (ejbLocalObject == null && con.getLocalHomeClass() != null) {
161: ejbLocalObject = ((EntityContainer) con)
162: .getLocalProxyFactory().getEntityEJBLocalObject(id);
163: }
164: return ejbLocalObject;
165: }
166:
167: public void setCacheKey(Object key) {
168: this .key = key;
169: }
170:
171: public Object getCacheKey() {
172: return key;
173: }
174:
175: public void setPersistenceContext(Object ctx) {
176: this .persistenceCtx = ctx;
177: }
178:
179: public Object getPersistenceContext() {
180: return persistenceCtx;
181: }
182:
183: public void hasTxSynchronization(boolean value) {
184: hasTxSynchronization = value;
185: }
186:
187: public boolean hasTxSynchronization() {
188: return hasTxSynchronization;
189: }
190:
191: public GlobalTxEntityMap.TxAssociation getTxAssociation() {
192: return txAssociation;
193: }
194:
195: public void setTxAssociation(
196: GlobalTxEntityMap.TxAssociation txAssociation) {
197: this .txAssociation = txAssociation;
198: }
199:
200: public void setValid(boolean valid) {
201: this .valid = valid;
202: }
203:
204: public boolean isValid() {
205: return valid;
206: }
207:
208: public void setReadOnly(boolean readOnly) {
209: this .readOnly = readOnly;
210: }
211:
212: public boolean isReadOnly() {
213: return readOnly;
214: }
215:
216: public boolean isPassivateAfterCommit() {
217: return passivateAfterCommit;
218: }
219:
220: public void setPassivateAfterCommit(boolean passivateAfterCommit) {
221: this .passivateAfterCommit = passivateAfterCommit;
222: }
223:
224: public String toString() {
225: return getContainer().getBeanMetaData().getEjbName() + '#'
226: + getId();
227: }
228:
229: protected class EntityContextImpl extends EJBContextImpl implements
230: EntityContext {
231: public EJBHome getEJBHome() {
232: AllowedOperationsAssociation.assertAllowedIn("getEJBHome",
233: IN_SET_ENTITY_CONTEXT | IN_UNSET_ENTITY_CONTEXT
234: | IN_EJB_CREATE | IN_EJB_POST_CREATE
235: | IN_EJB_REMOVE | IN_EJB_FIND | IN_EJB_HOME
236: | IN_EJB_ACTIVATE | IN_EJB_PASSIVATE
237: | IN_EJB_LOAD | IN_EJB_STORE
238: | IN_BUSINESS_METHOD | IN_EJB_TIMEOUT);
239:
240: return super .getEJBHome();
241: }
242:
243: public EJBLocalHome getEJBLocalHome() {
244: AllowedOperationsAssociation.assertAllowedIn(
245: "getEJBLocalHome", IN_SET_ENTITY_CONTEXT
246: | IN_UNSET_ENTITY_CONTEXT | IN_EJB_CREATE
247: | IN_EJB_POST_CREATE | IN_EJB_REMOVE
248: | IN_EJB_FIND | IN_EJB_HOME
249: | IN_EJB_ACTIVATE | IN_EJB_PASSIVATE
250: | IN_EJB_LOAD | IN_EJB_STORE
251: | IN_BUSINESS_METHOD | IN_EJB_TIMEOUT);
252:
253: return super .getEJBLocalHome();
254: }
255:
256: public Principal getCallerPrincipal() {
257: AllowedOperationsAssociation.assertAllowedIn(
258: "getCallerPrincipal", IN_EJB_CREATE
259: | IN_EJB_POST_CREATE | IN_EJB_REMOVE
260: | IN_EJB_FIND | IN_EJB_HOME | IN_EJB_LOAD
261: | IN_EJB_STORE | IN_BUSINESS_METHOD
262: | IN_EJB_TIMEOUT);
263:
264: return super .getCallerPrincipal();
265: }
266:
267: public boolean getRollbackOnly() {
268: AllowedOperationsAssociation.assertAllowedIn(
269: "getRollbackOnly", IN_EJB_CREATE
270: | IN_EJB_POST_CREATE | IN_EJB_REMOVE
271: | IN_EJB_FIND | IN_EJB_HOME | IN_EJB_LOAD
272: | IN_EJB_STORE | IN_BUSINESS_METHOD
273: | IN_EJB_TIMEOUT);
274:
275: return super .getRollbackOnly();
276: }
277:
278: public void setRollbackOnly() {
279: AllowedOperationsAssociation.assertAllowedIn(
280: "setRollbackOnly", IN_EJB_CREATE
281: | IN_EJB_POST_CREATE | IN_EJB_REMOVE
282: | IN_EJB_FIND | IN_EJB_HOME | IN_EJB_LOAD
283: | IN_EJB_STORE | IN_BUSINESS_METHOD
284: | IN_EJB_TIMEOUT);
285:
286: super .setRollbackOnly();
287: }
288:
289: public boolean isCallerInRole(String id) {
290: AllowedOperationsAssociation.assertAllowedIn(
291: "getCallerInRole", IN_EJB_CREATE
292: | IN_EJB_POST_CREATE | IN_EJB_REMOVE
293: | IN_EJB_FIND | IN_EJB_HOME | IN_EJB_LOAD
294: | IN_EJB_STORE | IN_BUSINESS_METHOD
295: | IN_EJB_TIMEOUT);
296: return super .isCallerInRole(id);
297: }
298:
299: public UserTransaction getUserTransaction() {
300: AllowedOperationsAssociation.assertAllowedIn(
301: "getUserTransaction", NOT_ALLOWED);
302: return super .getUserTransaction();
303: }
304:
305: public EJBObject getEJBObject() {
306: AllowedOperationsAssociation.assertAllowedIn(
307: "getEJBObject", IN_EJB_POST_CREATE | IN_EJB_REMOVE
308: | IN_EJB_ACTIVATE | IN_EJB_PASSIVATE
309: | IN_EJB_LOAD | IN_EJB_STORE
310: | IN_BUSINESS_METHOD | IN_EJB_TIMEOUT);
311:
312: if (((EntityContainer) con).getRemoteClass() == null) {
313: throw new IllegalStateException(
314: "No remote interface defined.");
315: }
316:
317: if (ejbObject == null) {
318: // Create a new CacheKey
319: Object cacheKey = ((EntityCache) ((EntityContainer) con)
320: .getInstanceCache()).createCacheKey(id);
321: EJBProxyFactory proxyFactory = con.getProxyFactory();
322: if (proxyFactory == null) {
323: String defaultInvokerName = con.getBeanMetaData()
324: .getContainerConfiguration()
325: .getDefaultInvokerName();
326: proxyFactory = con
327: .lookupProxyFactory(defaultInvokerName);
328: }
329: ejbObject = (EJBObject) proxyFactory
330: .getEntityEJBObject(cacheKey);
331: }
332:
333: return ejbObject;
334: }
335:
336: public EJBLocalObject getEJBLocalObject() {
337: AllowedOperationsAssociation.assertAllowedIn(
338: "getEJBLocalObject", IN_EJB_POST_CREATE
339: | IN_EJB_REMOVE | IN_EJB_ACTIVATE
340: | IN_EJB_PASSIVATE | IN_EJB_LOAD
341: | IN_EJB_STORE | IN_BUSINESS_METHOD
342: | IN_EJB_TIMEOUT);
343:
344: if (con.getLocalHomeClass() == null)
345: throw new IllegalStateException(
346: "No local interface for bean.");
347:
348: if (ejbLocalObject == null) {
349: Object cacheKey = ((EntityCache) ((EntityContainer) con)
350: .getInstanceCache()).createCacheKey(id);
351: ejbLocalObject = ((EntityContainer) con)
352: .getLocalProxyFactory()
353: .getEntityEJBLocalObject(cacheKey);
354: }
355: return ejbLocalObject;
356: }
357:
358: public Object getPrimaryKey() {
359: AllowedOperationsAssociation.assertAllowedIn(
360: "getPrimaryKey", IN_EJB_POST_CREATE | IN_EJB_REMOVE
361: | IN_EJB_ACTIVATE | IN_EJB_PASSIVATE
362: | IN_EJB_LOAD | IN_EJB_STORE
363: | IN_BUSINESS_METHOD | IN_EJB_TIMEOUT);
364:
365: return id;
366: }
367:
368: public TimerService getTimerService()
369: throws IllegalStateException {
370: AllowedOperationsAssociation.assertAllowedIn(
371: "getTimerService", IN_EJB_CREATE
372: | IN_EJB_POST_CREATE | IN_EJB_REMOVE
373: | IN_EJB_HOME | IN_EJB_ACTIVATE
374: | IN_EJB_PASSIVATE | IN_EJB_LOAD
375: | IN_EJB_STORE | IN_BUSINESS_METHOD
376: | IN_EJB_TIMEOUT);
377:
378: return new TimerServiceWrapper(this , getContainer()
379: .getTimerService(id));
380: }
381: }
382:
383: /**
384: * Delegates to the underlying TimerService, after checking access
385: */
386: public class TimerServiceWrapper implements TimerService {
387:
388: //private EnterpriseContext.EJBContextImpl context;
389: private TimerService timerService;
390:
391: public TimerServiceWrapper(
392: EnterpriseContext.EJBContextImpl ctx,
393: TimerService timerService) {
394: //this.context = ctx;
395: this .timerService = timerService;
396: }
397:
398: public Timer createTimer(long duration, Serializable info)
399: throws IllegalArgumentException, IllegalStateException,
400: EJBException {
401: assertAllowedIn("TimerService.createTimer");
402: return timerService.createTimer(duration, info);
403: }
404:
405: public Timer createTimer(long initialDuration,
406: long intervalDuration, Serializable info)
407: throws IllegalArgumentException, IllegalStateException,
408: EJBException {
409: assertAllowedIn("TimerService.createTimer");
410: return timerService.createTimer(initialDuration,
411: intervalDuration, info);
412: }
413:
414: public Timer createTimer(Date expiration, Serializable info)
415: throws IllegalArgumentException, IllegalStateException,
416: EJBException {
417: assertAllowedIn("TimerService.createTimer");
418: return timerService.createTimer(expiration, info);
419: }
420:
421: public Timer createTimer(Date initialExpiration,
422: long intervalDuration, Serializable info)
423: throws IllegalArgumentException, IllegalStateException,
424: EJBException {
425: assertAllowedIn("TimerService.createTimer");
426: return timerService.createTimer(initialExpiration,
427: intervalDuration, info);
428: }
429:
430: public Collection getTimers() throws IllegalStateException,
431: EJBException {
432: assertAllowedIn("TimerService.getTimers");
433: return timerService.getTimers();
434: }
435:
436: private void assertAllowedIn(String timerMethod) {
437: AllowedOperationsAssociation.assertAllowedIn(timerMethod,
438: IN_EJB_POST_CREATE | IN_EJB_REMOVE | IN_EJB_LOAD
439: | IN_EJB_STORE | IN_BUSINESS_METHOD
440: | IN_EJB_TIMEOUT);
441: }
442: }
443: }
|