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.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.rmi.RemoteException;
028: import java.security.Principal;
029: import java.util.Collection;
030: import java.util.Date;
031: import javax.ejb.EJBContext;
032: import javax.ejb.EJBException;
033: import javax.ejb.EJBHome;
034: import javax.ejb.EJBLocalHome;
035: import javax.ejb.MessageDrivenBean;
036: import javax.ejb.MessageDrivenContext;
037: import javax.ejb.Timer;
038: import javax.ejb.TimerService;
039: import javax.transaction.UserTransaction;
040:
041: import org.jboss.metadata.MessageDrivenMetaData;
042: import org.jboss.metadata.MetaData;
043:
044: /**
045: * Context for message driven beans.
046: *
047: * @author <a href="mailto:peter.antman@tim.se">Peter Antman</a>.
048: * @author <a href="mailto:rickard.oberg@telkel.com">Rickard �berg</a>
049: * @author <a href="sebastien.alborini@m4x.org">Sebastien Alborini</a>
050: * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
051: * @version <tt>$Revision: 57209 $</tt>
052: */
053: public class MessageDrivenEnterpriseContext extends EnterpriseContext {
054: private MessageDrivenContext ctx;
055:
056: /**
057: * Construct a <tt>MessageDrivenEnterpriseContext</tt>.
058: *
059: * <p>Sets the MDB context and calls ejbCreate().
060: *
061: * @param instance An instance of MessageDrivenBean
062: * @param con The container for this MDB.
063: *
064: * @throws Exception EJBException, Error or Exception. If RuntimeException
065: * was thrown by ejbCreate it will be turned into an
066: * EJBException.
067: */
068: public MessageDrivenEnterpriseContext(Object instance, Container con)
069: throws Exception {
070: super (instance, con);
071:
072: ctx = new MessageDrivenContextImpl();
073: ((MessageDrivenBean) instance).setMessageDrivenContext(ctx);
074:
075: try {
076: AllowedOperationsAssociation
077: .pushInMethodFlag(IN_EJB_CREATE);
078: Method ejbCreate = instance.getClass().getMethod(
079: "ejbCreate", new Class[0]);
080: ejbCreate.invoke(instance, new Object[0]);
081: } catch (InvocationTargetException e) {
082: Throwable t = e.getTargetException();
083:
084: if (t instanceof RuntimeException) {
085: if (t instanceof EJBException) {
086: throw (EJBException) t;
087: } else {
088: // Transform runtime exception into what a bean *should* have thrown
089: throw new EJBException((RuntimeException) t);
090: }
091: } else if (t instanceof Exception) {
092: throw (Exception) t;
093: } else if (t instanceof Error) {
094: throw (Error) t;
095: } else {
096: throw new org.jboss.util.NestedError(
097: "Unexpected Throwable", t);
098: }
099: }
100: }
101:
102: public MessageDrivenContext getMessageDrivenContext() {
103: return ctx;
104: }
105:
106: // EnterpriseContext overrides -----------------------------------
107:
108: /**
109: * Calls ejbRemove() on the MDB instance.
110: */
111: public void discard() throws RemoteException {
112: ((MessageDrivenBean) instance).ejbRemove();
113: }
114:
115: public EJBContext getEJBContext() {
116: return ctx;
117: }
118:
119: /**
120: * The EJBContext for MDBs.
121: */
122: protected class MessageDrivenContextImpl extends EJBContextImpl
123: implements MessageDrivenContext {
124:
125: public EJBHome getEJBHome() {
126: throw new IllegalStateException(
127: "getEJBHome should not be access from a message driven bean");
128: }
129:
130: public EJBLocalHome getEJBLocalHome() {
131: throw new IllegalStateException(
132: "getEJBHome should not be access from a message driven bean");
133: }
134:
135: public TimerService getTimerService()
136: throws IllegalStateException {
137: AllowedOperationsAssociation.assertAllowedIn(
138: "getTimerService", IN_EJB_CREATE | IN_EJB_REMOVE
139: | IN_BUSINESS_METHOD | IN_EJB_TIMEOUT);
140: return new TimerServiceWrapper(this , super
141: .getTimerService());
142: }
143:
144: public Principal getCallerPrincipal() {
145: AllowedOperationsAssociation.assertAllowedIn(
146: "getCallerPrincipal", IN_BUSINESS_METHOD
147: | IN_EJB_TIMEOUT);
148: return super .getCallerPrincipal();
149: }
150:
151: public boolean isCallerInRole(String id) {
152: throw new IllegalStateException(
153: "isCallerInRole should not be access from a message driven bean");
154: }
155:
156: public UserTransaction getUserTransaction() {
157: if (isContainerManagedTx())
158: throw new IllegalStateException(
159: "getUserTransaction should not be access for container managed Tx");
160:
161: AllowedOperationsAssociation.assertAllowedIn(
162: "getUserTransaction", IN_EJB_CREATE | IN_EJB_REMOVE
163: | IN_BUSINESS_METHOD | IN_EJB_TIMEOUT);
164:
165: return super .getUserTransaction();
166: }
167:
168: /**
169: * If transaction type is not Container or there is no transaction
170: * then throw an exception.
171: *
172: * @throws IllegalStateException If transaction type is not Container,
173: * or no transaction.
174: */
175: public boolean getRollbackOnly() {
176: if (isUserManagedTx())
177: throw new IllegalStateException(
178: "getRollbackOnly should not be access for user managed Tx");
179:
180: AllowedOperationsAssociation.assertAllowedIn(
181: "getRollbackOnly", IN_BUSINESS_METHOD
182: | IN_EJB_TIMEOUT);
183:
184: //
185: // jason: I think this is lame... but the spec says this is how it is.
186: // I think it would be better to silently ignore... or not so silently
187: // but still continue.
188: //
189:
190: if (!isTxRequired()) {
191: throw new IllegalStateException(
192: "getRollbackOnly must only be called in the context of a transaction (EJB 2.0 - 15.5.1)");
193: }
194:
195: return super .getRollbackOnly();
196: }
197:
198: /**
199: * If transaction type is not Container or there is no transaction
200: * then throw an exception.
201: *
202: * @throws IllegalStateException If transaction type is not Container,
203: * or no transaction.
204: */
205: public void setRollbackOnly() {
206: if (isUserManagedTx())
207: throw new IllegalStateException(
208: "setRollbackOnly should not be access for user managed Tx");
209:
210: AllowedOperationsAssociation.assertAllowedIn(
211: "getRollbackOnly", IN_BUSINESS_METHOD
212: | IN_EJB_TIMEOUT);
213:
214: if (!isTxRequired()) {
215: throw new IllegalStateException(
216: "setRollbackOnly must only be called in the context of a transaction (EJB 2.0 - 15.5.1)");
217: }
218:
219: super .setRollbackOnly();
220: }
221:
222: /** Helper to check if the tx type is TX_REQUIRED. */
223: private boolean isTxRequired() {
224: MessageDrivenMetaData md = (MessageDrivenMetaData) con
225: .getBeanMetaData();
226: return md.getMethodTransactionType() == MetaData.TX_REQUIRED;
227: }
228: }
229:
230: /**
231: * Delegates to the underlying TimerService, after checking access
232: */
233: public class TimerServiceWrapper implements TimerService {
234:
235: private EnterpriseContext.EJBContextImpl context;
236: private TimerService timerService;
237:
238: public TimerServiceWrapper(
239: EnterpriseContext.EJBContextImpl ctx,
240: TimerService timerService) {
241: this .context = ctx;
242: this .timerService = timerService;
243: }
244:
245: public Timer createTimer(long duration, Serializable info)
246: throws IllegalArgumentException, IllegalStateException,
247: EJBException {
248: assertAllowedIn("TimerService.createTimer");
249: return timerService.createTimer(duration, info);
250: }
251:
252: public Timer createTimer(long initialDuration,
253: long intervalDuration, Serializable info)
254: throws IllegalArgumentException, IllegalStateException,
255: EJBException {
256: assertAllowedIn("TimerService.createTimer");
257: return timerService.createTimer(initialDuration,
258: intervalDuration, info);
259: }
260:
261: public Timer createTimer(Date expiration, Serializable info)
262: throws IllegalArgumentException, IllegalStateException,
263: EJBException {
264: assertAllowedIn("TimerService.createTimer");
265: return timerService.createTimer(expiration, info);
266: }
267:
268: public Timer createTimer(Date initialExpiration,
269: long intervalDuration, Serializable info)
270: throws IllegalArgumentException, IllegalStateException,
271: EJBException {
272: assertAllowedIn("TimerService.createTimer");
273: return timerService.createTimer(initialExpiration,
274: intervalDuration, info);
275: }
276:
277: public Collection getTimers() throws IllegalStateException,
278: EJBException {
279: assertAllowedIn("TimerService.getTimers");
280: return timerService.getTimers();
281: }
282:
283: private void assertAllowedIn(String timerMethod) {
284: AllowedOperationsAssociation.assertAllowedIn(timerMethod,
285: IN_BUSINESS_METHOD | IN_EJB_TIMEOUT);
286: }
287: }
288: }
|