001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2005 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: JContext.java 7525 2005-10-19 10:43:24Z durieuxp $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.container;
025:
026: import java.security.Identity;
027: import java.security.Principal;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.Properties;
031:
032: import javax.ejb.EJBContext;
033: import javax.ejb.EJBHome;
034: import javax.ejb.EJBLocalHome;
035: import javax.ejb.EnterpriseBean;
036: import javax.ejb.TimerService;
037: import javax.resource.spi.work.WorkManager;
038: import javax.transaction.Status;
039: import javax.transaction.SystemException;
040: import javax.transaction.UserTransaction;
041:
042: import org.objectweb.transaction.jta.TransactionManager;
043:
044: import org.objectweb.jonas_lib.deployment.api.SecurityRoleRefDesc;
045:
046: import org.objectweb.util.monolog.api.BasicLevel;
047:
048: /**
049: * This class implements javax.ejb.EJBContext class.
050: * It may be extended in JSessionContext or JEntityContext
051: * @author Philippe Coq, Philippe Durieux, Jeff Mesnil (security)
052: * @author Florent Benoit (JACC security)
053: */
054: public abstract class JContext implements EJBContext {
055:
056: protected EnterpriseBean myinstance;
057: protected final JFactory bf;
058: protected final TransactionManager tm;
059: private final JHome home;
060: private final JLocalHome localhome;
061: private final JContainer cont;
062:
063: /**
064: * Permission manager of this container. JACC
065: */
066: private PermissionManager permissionManager = null;
067:
068: /**
069: * State of this Context
070: * 0 = init, 1 = setContext done, 2 = ejbCreate done.
071: */
072: int instanceState = 0;
073:
074: // ------------------------------------------------------------------
075: // constructors
076: // ------------------------------------------------------------------
077:
078: /**
079: * Constructs a JContext
080: * @param bf - the BeanFactory
081: * @param i - the bean instance
082: */
083: protected JContext(JFactory bf, EnterpriseBean i) {
084: this .bf = bf;
085: myinstance = i;
086: if (i == null) {
087: TraceEjb.logger.log(BasicLevel.ERROR,
088: "null EnterpriseBean!");
089: }
090: this .home = bf.getHome();
091: this .localhome = bf.getLocalHome();
092: this .cont = bf.getContainer();
093: this .tm = bf.getTransactionManager();
094: this .permissionManager = cont.getPermissionManager();
095:
096: }
097:
098: /**
099: * Set the instance State
100: */
101: public void setState(int newState) {
102: instanceState = newState;
103: if (TraceEjb.isDebugContext()) {
104: TraceEjb.context.log(BasicLevel.DEBUG, "" + instanceState);
105: }
106: }
107:
108: /**
109: * Get the Instance State
110: * @throws Exception
111: */
112: public int getState() {
113: if (TraceEjb.isDebugContext()) {
114: TraceEjb.context.log(BasicLevel.DEBUG, "" + instanceState);
115: }
116: return instanceState;
117: }
118:
119: // ------------------------------------------------------------------
120: // JOnAS specific added functions
121: // ------------------------------------------------------------------
122:
123: /**
124: * Get the WorkManager
125: */
126: public WorkManager getWorkManager() {
127: return bf.getWorkManager();
128: }
129:
130: // ------------------------------------------------------------------
131: // EJBContext implementation
132: // ------------------------------------------------------------------
133:
134: /**
135: * Obtains the java.security.Identity of the caller.
136: * @deprecated
137: * @return The Identity object that identifies the caller.
138: */
139: public Identity getCallerIdentity() {
140: throw new RuntimeException(
141: "getCallerIdentity() method deprecated. use instead getCallerPrincipal()");
142: }
143:
144: /**
145: * Obtain the java.security.Principal that identifies the caller.
146: * throws a java.lang.IllegalStateException if there is no security context available
147: * @return The Principal object that identifies the caller.
148: * @throws IllegalStateException no security context exists
149: */
150: public Principal getCallerPrincipal() throws IllegalStateException {
151:
152: if (getState() == 0) {
153: throw new IllegalStateException(
154: "the instance is not allowed to call this method");
155: }
156: boolean inRunAs = false;
157: if (bf.dd.getRunAsRole() != null) {
158: inRunAs = true;
159: }
160:
161: Principal principal = cont.getPrincipalFactory()
162: .getCallerPrincipal(inRunAs);
163: if (principal == null) {
164: throw new IllegalStateException(
165: "no security context exists");
166: }
167: return principal;
168:
169: }
170:
171: /**
172: * the enterprise bean's home interface.
173: * @return The enterprise bean's home interface.
174: * @throws IllegalStateException - if the enterprise bean does not have a local home interface.
175: */
176: public EJBHome getEJBHome() throws IllegalStateException {
177: return home;
178: }
179:
180: /**
181: * Obtain the enterprise bean's local home interface.
182: * @return The enterprise bean's local home interface.
183: * @throws IllegalStateException if the enterprise bean does not have a local home interface.
184: */
185: public EJBLocalHome getEJBLocalHome() throws IllegalStateException {
186: if (!bf.dd.hasDefinedLocalInterface()) {
187: TraceEjb.logger.log(BasicLevel.ERROR,
188: "No Local Interface declared for this bean");
189: throw new IllegalStateException(
190: "No Local Interface declared for this bean");
191: }
192: return localhome;
193: }
194:
195: /**
196: * Obtains the enterprise bean's environment properties for EJB 1.0 style.
197: * (Conform to EJB 1.1 specification for a container chooses to provide support
198: * for EJB 1.0 style environment properties. Cf EJB 1.1 Chapter 14.5, pages 216-217)
199: * Note: If the enterprise bean has no environment properties, this method returns an empty
200: * java.util.Properties object. This method never returns null.
201: * @deprecated
202: * @return The environment properties for the enterprise bean.
203: */
204: public Properties getEnvironment() {
205: if (TraceEjb.isDebugIc()) {
206: TraceEjb.interp.log(BasicLevel.DEBUG, "");
207: }
208: return bf.getEjb10Environment();
209: }
210:
211: /**
212: * Tests if the transaction has been marked for rollback only.
213: * @return true if transaction will rollback
214: * @throws IllegalStateException if state is 0
215: */
216: public boolean getRollbackOnly() throws IllegalStateException {
217: if (TraceEjb.isDebugIc()) {
218: TraceEjb.interp.log(BasicLevel.DEBUG, "");
219: }
220:
221: if (getState() == 0) {
222: throw new IllegalStateException(
223: "the instance is not allowed to call this method");
224: }
225:
226: try {
227: switch (tm.getStatus()) {
228: case Status.STATUS_MARKED_ROLLBACK:
229: case Status.STATUS_ROLLING_BACK:
230: return true;
231: case Status.STATUS_ACTIVE:
232: case Status.STATUS_COMMITTING:
233: case Status.STATUS_PREPARED:
234: case Status.STATUS_PREPARING:
235: return false;
236: case Status.STATUS_ROLLEDBACK:
237: throw new IllegalStateException(
238: "Transaction already rolled back");
239: case Status.STATUS_COMMITTED:
240: throw new IllegalStateException(
241: "Transaction already committed");
242: case Status.STATUS_NO_TRANSACTION:
243: case Status.STATUS_UNKNOWN:
244: throw new IllegalStateException(
245: "Cannot getRollbackOnly outside transaction");
246: }
247: } catch (SystemException e) {
248: TraceEjb.logger.log(BasicLevel.ERROR,
249: "cannot get transaction status:", e);
250: throw new IllegalStateException(
251: "Cannot get transaction status");
252: }
253: return true;
254: }
255:
256: /**
257: * Get access to the EJB Timer Service.
258: * @return the EJB Timer Service
259: * @throws IllegalStateException Thrown if the instance is not
260: * allowed to use this method (e.g. if the bean is a stateful session bean)
261: */
262: public abstract TimerService getTimerService()
263: throws IllegalStateException;
264:
265: /**
266: * Obtains the transaction demarcation interface.
267: * @return The UserTransaction interface that the enterprise bean instance
268: * can use for transaction demarcation.
269: * @throws IllegalStateException Thrown if the instance container does
270: * not make the UserTransaction interface available to the
271: * instance. (not bean managed)
272: */
273: public UserTransaction getUserTransaction()
274: throws IllegalStateException {
275:
276: if (TraceEjb.isDebugIc()) {
277: TraceEjb.interp.log(BasicLevel.DEBUG, "");
278: }
279:
280: if (!bf.isTxBeanManaged()) {
281: throw new IllegalStateException(
282: "This bean is not allowed to use UserTransaction interface");
283: }
284: if (getState() == 0) {
285: throw new IllegalStateException(
286: "the instance is not allowed to call this method");
287: }
288: return (UserTransaction) tm;
289: }
290:
291: /**
292: * @deprecated Use boolean isCallerInRole(String roleName) instead.
293: * Tests if the caller has a given role.
294: * @param role - The java.security.Identity of the role to be tested.
295: * @return True if the caller has the specified role.
296: */
297: public boolean isCallerInRole(Identity role) {
298: throw new RuntimeException(
299: "isCallerInRole(Identity) method deprecated. use instead isCallerInRole(String)");
300: }
301:
302: /**
303: * Test if the caller has a given role.
304: *
305: * @param roleName The name of the security role.
306: * The role must be one of the security-role-ref that is defined in the
307: * deployment descriptor.
308: * @return True if the caller has the specified role.
309: * @throws IllegalStateException Security service not started
310: */
311: public boolean isCallerInRole(String roleName)
312: throws IllegalStateException {
313: if (TraceEjb.isDebugSecurity()) {
314: TraceEjb.security.log(BasicLevel.DEBUG, "");
315: }
316:
317: if (getState() == 0) {
318: throw new IllegalStateException(
319: "the instance is not allowed to call this method");
320: }
321:
322: // See EJB 2.1 specification
323: // Chapter 21 : 21.2.5.2
324:
325: // Check that the roleName is in security-role-ref
326: List list = bf.dd.getSecurityRoleRefDescList();
327:
328: if (list == null) {
329: TraceEjb.logger
330: .log(
331: BasicLevel.WARN,
332: "EJB 2.1 spec, Chapter 21 : 21.2.5.2 : No security-role-ref list. Invalid usage of isCallerInRole without security-role-ref elements.");
333: return false;
334: }
335: boolean foundItem = false;
336: Iterator it = bf.dd.getSecurityRoleRefDescList().iterator();
337: String tmpRoleName = null;
338: SecurityRoleRefDesc sRoleRefDesc = null;
339: while (!foundItem && it.hasNext()) {
340: sRoleRefDesc = (SecurityRoleRefDesc) it.next();
341: tmpRoleName = sRoleRefDesc.getRoleName();
342: if (tmpRoleName.equals(roleName)) {
343: foundItem = true;
344: }
345: }
346:
347: if (!foundItem) {
348: if (TraceEjb.isDebugSecurity()) {
349: TraceEjb.security
350: .log(
351: BasicLevel.DEBUG,
352: "No security-role-ref with role name '"
353: + roleName
354: + "' was found in the deployment descriptor of bean '"
355: + bf.getEJBName() + ".");
356: }
357: return false;
358: }
359:
360: boolean inRunAs = false;
361: if (bf.dd.getRunAsRole() != null) {
362: inRunAs = true;
363: }
364: // Check with JACC manager
365: boolean inRole = permissionManager.isCallerInRole(bf
366: .getEJBName(), roleName, inRunAs);
367:
368: if (TraceEjb.isDebugSecurity()) {
369: TraceEjb.security.log(BasicLevel.DEBUG, "isCallerInRole: "
370: + inRole);
371: }
372: return inRole;
373:
374: }
375:
376: /**
377: * Marks the current transaction for rollback.
378: * The transaction will become permanently marked for rollback.
379: * @throws IllegalStateException in getRollbackOnly() method
380: */
381: public void setRollbackOnly() throws IllegalStateException {
382: if (TraceEjb.isDebugIc()) {
383: TraceEjb.interp.log(BasicLevel.DEBUG, "");
384: }
385:
386: // Check transaction state.
387: // Should throw IllegalStateException if not in a correct state.
388: // This may be not handled correctly by the TM.
389: getRollbackOnly();
390:
391: try {
392: tm.setRollbackOnly();
393: } catch (IllegalStateException e) {
394: TraceEjb.logger.log(BasicLevel.ERROR,
395: "current thread not associated with transaction");
396: throw e;
397: } catch (SystemException e) {
398: TraceEjb.logger.log(BasicLevel.ERROR,
399: "setRollbackOnly unexpected exception:", e);
400: }
401: }
402:
403: }
|