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: JMessageEndpoint.java 6673 2005-04-28 16:53:00Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.container;
025:
026: import java.security.Identity;
027: import java.security.Principal;
028: import java.util.Properties;
029:
030: import javax.ejb.EJBException;
031: import javax.ejb.EJBHome;
032: import javax.ejb.EJBLocalHome;
033: import javax.ejb.MessageDrivenBean;
034: import javax.ejb.MessageDrivenContext;
035: import javax.ejb.TimedObject;
036: import javax.ejb.Timer;
037: import javax.ejb.TimerService;
038: import javax.resource.spi.endpoint.MessageEndpoint;
039: import javax.transaction.Status;
040: import javax.transaction.SystemException;
041: import javax.transaction.UserTransaction;
042: import javax.transaction.xa.XAResource;
043:
044: import org.objectweb.jonas_ejb.deployment.api.MethodDesc;
045:
046: import org.objectweb.security.context.SecurityContext;
047: import org.objectweb.security.context.SecurityCurrent;
048:
049: import org.objectweb.transaction.jta.TransactionManager;
050: import org.objectweb.util.monolog.api.BasicLevel;
051:
052: /**
053: * Generic interposed class for Message Endpoints This class presents these
054: * interfaces, depending on object reached: MessageDrivenContext interface to
055: * the bean instance
056: * @author Philippe Coq, Philippe Durieux
057: * @author Christophe Ney (Easier Enhydra integration)
058: */
059: public class JMessageEndpoint implements MessageDrivenContext {
060:
061: protected JMdbEndpointFactory bf = null;
062:
063: protected MessageDrivenBean mdb = null;
064:
065: protected MessageEndpoint mep = null;
066:
067: protected int txattr; // TX_NOT_SUPPORTED, TX_REQUIRED or TX_NOT_SET (= bean
068: // managed)
069:
070: protected TransactionManager tm = null;
071:
072: protected XAResource xar = null;
073:
074: protected boolean released = false;
075:
076: private static final int MAX_NB_RETRY = 2;
077:
078: /**
079: * constructor
080: * @param bf The MDB Endpoint Factory
081: * @param mdb The Message Driven Bean
082: */
083: public JMessageEndpoint(JMdbEndpointFactory bf,
084: MessageDrivenBean mdb) {
085: this .bf = bf;
086: this .mdb = mdb;
087: // keep these locally for efficiency.
088: txattr = bf.getTransactionAttribute();
089: tm = bf.getTransactionManager();
090: }
091:
092: public void setProxy(MessageEndpoint mep) {
093: this .mep = mep;
094: }
095:
096: public XAResource getXAResource() {
097: return xar;
098: }
099:
100: public void setXAResource(XAResource xa) {
101: xar = xa;
102: // Check state of transaction to determine what to do
103: }
104:
105: public boolean getReleasedState() {
106: return released;
107: }
108:
109: public void setReleasedState(boolean state) {
110: released = state;
111: }
112:
113: // ------------------------------------------------------------------
114: // EJBContext implementation
115: // ------------------------------------------------------------------
116:
117: /**
118: * Get access to the EJB Timer Service.
119: * @return the EJB Timer Service
120: * @throws IllegalStateException Thrown if the instance is not allowed to
121: * use this method
122: */
123: public TimerService getTimerService() throws IllegalStateException {
124: if (TraceEjb.isDebugIc()) {
125: TraceEjb.interp.log(BasicLevel.DEBUG, "");
126: }
127: return bf.getTimerService();
128: }
129:
130: // ----------------------------------------------------------------------
131: // javax.ejb.MessageDrivenContext implementation
132: // ----------------------------------------------------------------------
133:
134: private static final String DISALLOWED_MSG = " is disallowed in a message driven bean";
135:
136: /**
137: * Obtains the java.security.Identity of the caller. disallowed in
138: * messagedriven bean method because there is no security context
139: * @deprecated @exception java.lang.IllegalStateException always
140: */
141: public Identity getCallerIdentity() {
142: TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
143: throw new IllegalStateException("getCallerIdentity()"
144: + DISALLOWED_MSG);
145: }
146:
147: /**
148: * @return the java.security.Principal that identifies the caller.
149: * @throws IllegalStateException if there is no principal
150: */
151: public Principal getCallerPrincipal() {
152: boolean inRunAs = false;
153: if (bf.dd.getRunAsRole() != null) {
154: inRunAs = true;
155: }
156: // Set a security context if there was no one set.
157: SecurityCurrent current = SecurityCurrent.getCurrent();
158: if (current != null) {
159: SecurityContext sctx = current.getSecurityContext();
160: if (sctx == null) {
161: if (TraceEjb.isDebugSecurity()) {
162: TraceEjb.security
163: .log(BasicLevel.DEBUG,
164: "runas : Security context is null, create a new one");
165: }
166: sctx = new SecurityContext();
167: current.setSecurityContext(sctx);
168: }
169: }
170:
171: Principal principal = bf.getContainer().getPrincipalFactory()
172: .getCallerPrincipal(inRunAs);
173: if (principal == null) {
174: throw new IllegalStateException(
175: "No principal exists in security context");
176: }
177: return principal;
178: }
179:
180: /**
181: * Test if the caller has a given role.
182: * @deprecated @throws java.lang.IllegalStateException for message driven
183: * bean because there is no security context available
184: */
185: public boolean isCallerInRole(Identity role) {
186: TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
187: throw new IllegalStateException("isCallerInRole()"
188: + DISALLOWED_MSG);
189: }
190:
191: /**
192: * Test if the caller has a given role.
193: * @throws java.lang.IllegalStateException for message driven bean because
194: * there is no security context available
195: */
196: public boolean isCallerInRole(java.lang.String roleLink) {
197: TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
198: throw new IllegalStateException("isCallerInRole()"
199: + DISALLOWED_MSG);
200: }
201:
202: /**
203: * Marks the current transaction for rollback. Should be used only if the
204: * instance is associated with a transaction
205: * @throws java.lang.IllegalStateException if the instance is not associated
206: * with a transaction
207: */
208: public void setRollbackOnly() {
209:
210: if (TraceEjb.isDebugJms()) {
211: TraceEjb.mdb.log(BasicLevel.DEBUG, "");
212: }
213:
214: if (bf.isTxBeanManaged())
215: throw new IllegalStateException(
216: "Bean-managed transaction, not use this method.");
217: try {
218: tm.setRollbackOnly();
219: } catch (IllegalStateException e) {
220: TraceEjb.logger.log(BasicLevel.ERROR,
221: "current thread not associated with transaction");
222: throw e;
223: } catch (SystemException e) {
224: TraceEjb.logger.log(BasicLevel.ERROR,
225: "unexpected exception:", e);
226: }
227: }
228:
229: /**
230: * Tests if the transaction has been marked for rollback only.
231: * @return True if transaction has been marked for rollback.
232: */
233: public boolean getRollbackOnly() {
234: if (TraceEjb.isDebugJms()) {
235: TraceEjb.mdb.log(BasicLevel.DEBUG, "");
236: }
237: if (bf.isTxBeanManaged())
238: throw new IllegalStateException(
239: "Bean-managed transaction, not use this method.");
240: try {
241: if (tm.getTransaction() != null) {
242: switch (tm.getStatus()) {
243: case Status.STATUS_MARKED_ROLLBACK:
244: case Status.STATUS_ROLLEDBACK:
245: case Status.STATUS_ROLLING_BACK:
246: return true;
247: case Status.STATUS_NO_TRANSACTION:
248: throw new IllegalStateException("No transaction");
249: default:
250: return false;
251: }
252: } else {
253: TraceEjb.logger.log(BasicLevel.ERROR,
254: "the bean is not associated in a transaction");
255: throw new IllegalStateException(
256: "the message driven bean is not associated in a transaction");
257: }
258: } catch (SystemException e) {
259: TraceEjb.logger.log(BasicLevel.ERROR, "cannot get status:",
260: e);
261: return false;
262: }
263: }
264:
265: /**
266: * Is disallowed. There is no home for message driven bean.
267: * @throws IllegalStateException Always.
268: */
269: public EJBHome getEJBHome() {
270: TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
271: throw new IllegalStateException("getEJBHome()" + DISALLOWED_MSG);
272: }
273:
274: /**
275: * Is disallowed. There is no local home for message driven bean.
276: * @throws IllegalStateException Always.
277: */
278: public EJBLocalHome getEJBLocalHome() {
279: TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
280: throw new IllegalStateException("getEJBLocalHome()"
281: + DISALLOWED_MSG);
282: }
283:
284: /**
285: * @deprecated Use the JNDI naming context java:comp/env instead.
286: * @return properties for the bean.
287: */
288: public Properties getEnvironment() {
289: TraceEjb.logger
290: .log(BasicLevel.ERROR,
291: "deprecated use : Use the JNDI naming context java:comp/env");
292: return new java.util.Properties();
293: }
294:
295: /**
296: * Obtains the transaction demarcation interface.
297: * @return The UserTransaction interface that the enterprise bean instance
298: * can use for transaction demarcation.
299: * @exception IllegalStateException: Thrown if the instance container does
300: * not make the UserTransaction interface available to the
301: * instance.
302: */
303: public UserTransaction getUserTransaction()
304: throws IllegalStateException {
305:
306: if (TraceEjb.isDebugJms()) {
307: TraceEjb.mdb.log(BasicLevel.DEBUG, "");
308: }
309:
310: if (!bf.isTxBeanManaged()) {
311: throw new IllegalStateException(
312: "This bean is not allowed to use UserTransaction interface");
313: }
314: return (UserTransaction) tm;
315: }
316:
317: // -----------------------------------------------------------------------
318: // other public methods
319: // -----------------------------------------------------------------------
320:
321: /**
322: * Deliver a timeout to the bean
323: * @param timer timer whose expiration caused this notification.
324: */
325: public void deliverTimeout(Timer timer) {
326: if (TraceEjb.isDebugJms()) {
327: TraceEjb.mdb.log(BasicLevel.DEBUG, "");
328: }
329:
330: boolean committed = false;
331: for (int nbretry = 0; !committed && nbretry < MAX_NB_RETRY; nbretry++) {
332: RequestCtx rctx = null;
333: try {
334: // For MDB, transaction attribute must be required or NotSupported.
335: rctx = bf.preInvoke(MethodDesc.TX_REQUIRED);
336: } catch (Exception e) {
337: TraceEjb.logger.log(BasicLevel.ERROR,
338: "preInvoke failed: ", e);
339: return;
340: }
341: try {
342: bf.checkSecurity(null);
343: if (mdb instanceof TimedObject) {
344: ((TimedObject) mdb).ejbTimeout(timer);
345: } else {
346: throw new EJBException(
347: "The bean does not implement the `TimedObject` interface");
348: }
349: committed = !getRollbackOnly();
350: } catch (EJBException e) {
351: rctx.sysExc = e;
352: TraceEjb.logger
353: .log(
354: BasicLevel.ERROR,
355: "EJB exception thrown by an enterprise Bean",
356: e);
357: } catch (RuntimeException e) {
358: rctx.sysExc = e;
359: TraceEjb.logger
360: .log(
361: BasicLevel.ERROR,
362: "runtime exception thrown by an enterprise Bean",
363: e);
364: } catch (Error e) {
365: rctx.sysExc = e;
366: TraceEjb.logger.log(BasicLevel.ERROR,
367: "error thrown by an enterprise Bean", e);
368: } finally {
369: try {
370: bf.postInvoke(rctx);
371: } catch (Exception e) {
372: TraceEjb.logger.log(BasicLevel.ERROR,
373: "exception on postInvoke: ", e);
374: }
375: }
376: }
377: }
378: }
|