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: // $Id: AllowedOperationsAssociation.java 57209 2006-09-26 12:21:57Z dimitris@jboss.org $
025:
026: import java.util.ArrayList;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.LinkedHashMap;
030: import java.util.List;
031: import java.util.Map;
032: import java.util.Stack;
033:
034: import org.jboss.logging.Logger;
035:
036: /**
037: * Associates the current thread with a stack of flags that
038: * indicate the callers current ejb method.
039: *
040: * According to the EJB2.1 spec not all context methods can be accessed at all times
041: * For example ctx.getPrimaryKey() should throw an IllegalStateException when called from within ejbCreate()
042: *
043: * @author Thomas.Diesler@jboss.org
044: * @author Dimitris.Andreadis@jboss.org
045: * @version $Revision: 57209 $
046: */
047: public final class AllowedOperationsAssociation implements
048: AllowedOperationsFlags {
049: // provide logging
050: private static final Logger log = Logger
051: .getLogger(AllowedOperationsAssociation.class);
052:
053: // Constants -----------------------------------------------------
054:
055: public static final HashMap methodMap = new LinkedHashMap();
056: static {
057: methodMap.put(new Integer(IN_INTERCEPTOR_METHOD),
058: "IN_INTERCEPTOR_METHOD");
059: methodMap.put(new Integer(IN_EJB_ACTIVATE), "IN_EJB_ACTIVATE");
060: methodMap
061: .put(new Integer(IN_EJB_PASSIVATE), "IN_EJB_PASSIVATE");
062: methodMap.put(new Integer(IN_EJB_REMOVE), "IN_EJB_REMOVE");
063: methodMap.put(new Integer(IN_EJB_CREATE), "IN_EJB_CREATE");
064: methodMap.put(new Integer(IN_EJB_POST_CREATE),
065: "IN_EJB_POST_CREATE");
066: methodMap.put(new Integer(IN_EJB_FIND), "IN_EJB_FIND");
067: methodMap.put(new Integer(IN_EJB_HOME), "IN_EJB_HOME");
068: methodMap.put(new Integer(IN_EJB_TIMEOUT), "IN_EJB_TIMEOUT");
069: methodMap.put(new Integer(IN_EJB_LOAD), "IN_EJB_LOAD");
070: methodMap.put(new Integer(IN_EJB_STORE), "IN_EJB_STORE");
071: methodMap.put(new Integer(IN_SET_ENTITY_CONTEXT),
072: "IN_SET_ENTITY_CONTEXT");
073: methodMap.put(new Integer(IN_UNSET_ENTITY_CONTEXT),
074: "IN_UNSET_ENTITY_CONTEXT");
075: methodMap.put(new Integer(IN_SET_SESSION_CONTEXT),
076: "IN_SET_SESSION_CONTEXT");
077: methodMap.put(new Integer(IN_SET_MESSAGE_DRIVEN_CONTEXT),
078: "IN_SET_MESSAGE_DRIVEN_CONTEXT");
079: methodMap.put(new Integer(IN_AFTER_BEGIN), "IN_AFTER_BEGIN");
080: methodMap.put(new Integer(IN_BEFORE_COMPLETION),
081: "IN_BEFORE_COMPLETION");
082: methodMap.put(new Integer(IN_AFTER_COMPLETION),
083: "IN_AFTER_COMPLETION");
084: methodMap.put(new Integer(IN_BUSINESS_METHOD),
085: "IN_BUSINESS_METHOD");
086: methodMap.put(new Integer(IN_SERVICE_ENDPOINT_METHOD),
087: "IN_SERVICE_ENDPOINT_METHOD");
088: }
089:
090: /**
091: * Holds a stack of the IN_METHOD constants, to indicate that we are in an ejb method
092: */
093: private static ThreadLocal threadLocal = new ThreadLocal() {
094: protected Object initialValue() {
095: return new Stack();
096: }
097: };
098:
099: // Static --------------------------------------------------------
100:
101: /**
102: * Set when the instance enters an ejb method, reset on exit
103: *
104: * @param inMethodFlag one of the IN_METHOD contants or null
105: */
106: public static void pushInMethodFlag(int inMethodFlag) {
107: Stack inMethodStack = (Stack) threadLocal.get();
108: inMethodStack.push(new Integer(inMethodFlag));
109: }
110:
111: /**
112: * Reset when the instance exits an ejb method
113: */
114: public static void popInMethodFlag() {
115: Stack inMethodStack = (Stack) threadLocal.get();
116: inMethodStack.pop();
117: }
118:
119: /**
120: * Return the current inMethodFlag, or -1 if there is none
121: */
122: public static int peekInMethodFlag() {
123: Stack inMethodStack = (Stack) threadLocal.get();
124: if (inMethodStack.isEmpty() == false)
125: return ((Integer) inMethodStack.peek()).intValue();
126: else
127: return -1;
128: }
129:
130: /**
131: * Return the current inMethodFlag in String form,
132: * or null if there is none
133: */
134: public static String peekInMethodFlagAsString() {
135: int currentMethodFlag = peekInMethodFlag();
136:
137: return (String) methodMap.get(new Integer(currentMethodFlag));
138: }
139:
140: /**
141: * Throw an IllegalStateException if the current inMethodFlag
142: * does not match the given flags
143: */
144: public static void assertAllowedIn(String ctxMethod, int flags) {
145: Stack inMethodStack = (Stack) threadLocal.get();
146:
147: // Strict validation, the caller MUST set the in method flag
148: if (inMethodStack.empty()) {
149: throw new IllegalStateException(
150: "Cannot obtain inMethodFlag for: " + ctxMethod);
151: }
152:
153: // The container should push a method flag into the context just before
154: // a call to the instance method
155: if (inMethodStack.empty() == false) {
156: // Check if the given ctxMethod can be called from the ejb instance
157: // this relies on the inMethodFlag being pushed prior to the call to the ejb method
158: Integer inMethodFlag = ((Integer) inMethodStack.peek());
159: if ((inMethodFlag.intValue() & flags) == 0
160: && inMethodFlag.intValue() != IN_INTERCEPTOR_METHOD) {
161: String message = ctxMethod
162: + " should not be access from this bean method: "
163: + methodMap.get(inMethodFlag);
164: IllegalStateException ex = new IllegalStateException(
165: message);
166: log.error(message + ", allowed is "
167: + getAllowedMethodList(flags), ex);
168: throw ex;
169: }
170: }
171: }
172:
173: /**
174: * Get a list of strings corresponding to the given method flags
175: */
176: private static List getAllowedMethodList(int flags) {
177: ArrayList allowed = new ArrayList();
178: Iterator it = methodMap.entrySet().iterator();
179: while (it.hasNext()) {
180: Map.Entry entry = (Map.Entry) it.next();
181: Integer flag = (Integer) entry.getKey();
182: if ((flag.intValue() & flags) > 0)
183: allowed.add(entry.getValue());
184: }
185: return allowed;
186: }
187: }
|