001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.core.stateless;
017:
018: import java.lang.reflect.Method;
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023:
024: import javax.ejb.EJBAccessException;
025: import javax.ejb.EJBHome;
026: import javax.ejb.EJBLocalHome;
027: import javax.ejb.EJBLocalObject;
028: import javax.ejb.EJBObject;
029: import javax.interceptor.AroundInvoke;
030: import javax.transaction.TransactionManager;
031:
032: import org.apache.openejb.ContainerType;
033: import org.apache.openejb.DeploymentInfo;
034: import org.apache.openejb.OpenEJBException;
035: import org.apache.openejb.ProxyInfo;
036: import org.apache.openejb.InterfaceType;
037: import org.apache.openejb.core.CoreDeploymentInfo;
038: import org.apache.openejb.core.Operation;
039: import org.apache.openejb.core.ThreadContext;
040: import org.apache.openejb.core.ExceptionType;
041: import org.apache.openejb.core.interceptor.InterceptorData;
042: import org.apache.openejb.core.interceptor.InterceptorStack;
043: import org.apache.openejb.core.timer.EjbTimerService;
044: import org.apache.openejb.core.transaction.TransactionContainer;
045: import org.apache.openejb.core.transaction.TransactionContext;
046: import org.apache.openejb.core.transaction.TransactionPolicy;
047: import org.apache.openejb.spi.SecurityService;
048: import org.apache.xbean.finder.ClassFinder;
049:
050: /**
051: * @org.apache.xbean.XBean element="statelessContainer"
052: */
053: public class StatelessContainer implements
054: org.apache.openejb.RpcContainer, TransactionContainer {
055:
056: private StatelessInstanceManager instanceManager;
057:
058: private HashMap<String, DeploymentInfo> deploymentRegistry = new HashMap<String, DeploymentInfo>();
059:
060: private Object containerID = null;
061: private TransactionManager transactionManager;
062: private SecurityService securityService;
063:
064: public StatelessContainer(Object id,
065: TransactionManager transactionManager,
066: SecurityService securityService, int timeOut, int poolSize,
067: boolean strictPooling) throws OpenEJBException {
068: this .containerID = id;
069: this .transactionManager = transactionManager;
070: this .securityService = securityService;
071:
072: instanceManager = new StatelessInstanceManager(
073: transactionManager, securityService, timeOut, poolSize,
074: strictPooling);
075:
076: for (DeploymentInfo deploymentInfo : deploymentRegistry
077: .values()) {
078: org.apache.openejb.core.CoreDeploymentInfo di = (org.apache.openejb.core.CoreDeploymentInfo) deploymentInfo;
079: di.setContainer(this );
080: }
081: }
082:
083: public synchronized DeploymentInfo[] deployments() {
084: return deploymentRegistry.values().toArray(
085: new DeploymentInfo[deploymentRegistry.size()]);
086: }
087:
088: public synchronized DeploymentInfo getDeploymentInfo(
089: Object deploymentID) {
090: String id = (String) deploymentID;
091: return deploymentRegistry.get(id);
092: }
093:
094: public ContainerType getContainerType() {
095: return ContainerType.STATELESS;
096: }
097:
098: public Object getContainerID() {
099: return containerID;
100: }
101:
102: public void deploy(DeploymentInfo info) throws OpenEJBException {
103: CoreDeploymentInfo deploymentInfo = (CoreDeploymentInfo) info;
104: instanceManager.deploy(deploymentInfo);
105: String id = (String) deploymentInfo.getDeploymentID();
106: synchronized (this ) {
107: deploymentRegistry.put(id, deploymentInfo);
108: deploymentInfo.setContainer(this );
109: }
110:
111: EjbTimerService timerService = deploymentInfo
112: .getEjbTimerService();
113: if (timerService != null) {
114: timerService.start();
115: }
116: }
117:
118: public void undeploy(DeploymentInfo info) {
119: undeploy((CoreDeploymentInfo) info);
120: }
121:
122: private void undeploy(CoreDeploymentInfo deploymentInfo) {
123: instanceManager.undeploy(deploymentInfo);
124: EjbTimerService timerService = deploymentInfo
125: .getEjbTimerService();
126: if (timerService != null) {
127: timerService.stop();
128: }
129:
130: synchronized (this ) {
131: String id = (String) deploymentInfo.getDeploymentID();
132: deploymentInfo.setContainer(null);
133: deploymentInfo.setContainerData(null);
134: deploymentRegistry.remove(id);
135: }
136: }
137:
138: /**
139: * @deprecated use invoke signature without 'securityIdentity' argument.
140: */
141: public Object invoke(Object deployID, Method callMethod,
142: Object[] args, Object primKey, Object securityIdentity)
143: throws OpenEJBException {
144: return invoke(deployID, callMethod.getDeclaringClass(),
145: callMethod, args, primKey);
146: }
147:
148: public Object invoke(Object deployID, Class callInterface,
149: Method callMethod, Object[] args, Object primKey)
150: throws OpenEJBException {
151: CoreDeploymentInfo deployInfo = (CoreDeploymentInfo) this
152: .getDeploymentInfo(deployID);
153: if (deployInfo == null)
154: throw new OpenEJBException(
155: "Deployment does not exist in this container. Deployment(id='"
156: + deployID + "'), Container(id='"
157: + containerID + "')");
158:
159: ThreadContext callContext = new ThreadContext(deployInfo,
160: primKey);
161: ThreadContext oldCallContext = ThreadContext.enter(callContext);
162: try {
163: boolean authorized = getSecurityService()
164: .isCallerAuthorized(callMethod,
165: deployInfo.getInterfaceType(callInterface));
166: if (!authorized)
167: throw new org.apache.openejb.ApplicationException(
168: new EJBAccessException(
169: "Unauthorized Access by Principal Denied"));
170:
171: Class declaringClass = callMethod.getDeclaringClass();
172: if (EJBHome.class.isAssignableFrom(declaringClass)
173: || EJBLocalHome.class
174: .isAssignableFrom(declaringClass)) {
175: if (callMethod.getName().startsWith("create")) {
176: return createEJBObject(deployInfo, callMethod);
177: } else
178: return null;// EJBHome.remove( ) and other EJBHome methods are not process by the container
179: } else if (EJBObject.class == declaringClass
180: || EJBLocalObject.class == declaringClass) {
181: return null;// EJBObject.remove( ) and other EJBObject methods are not process by the container
182: }
183:
184: Object bean = instanceManager.getInstance(callContext);
185:
186: callContext.setCurrentOperation(Operation.BUSINESS);
187: callContext.setCurrentAllowedStates(StatelessContext
188: .getStates());
189:
190: Method runMethod = deployInfo
191: .getMatchingBeanMethod(callMethod);
192:
193: callContext.set(Method.class, runMethod);
194: callContext.setInvokedInterface(callInterface);
195: Object retValue = _invoke(callInterface, callMethod,
196: runMethod, args, bean, callContext);
197: instanceManager.poolInstance(callContext, bean);
198:
199: return retValue;
200:
201: } finally {
202: ThreadContext.exit(oldCallContext);
203: }
204: }
205:
206: private SecurityService getSecurityService() {
207: return securityService;
208: }
209:
210: public StatelessInstanceManager getInstanceManager() {
211: return instanceManager;
212: }
213:
214: /**
215: * @deprecated use type-safe {@link #_invoke(Class, java.lang.reflect.Method, java.lang.reflect.Method, Object[], Instance, org.apache.openejb.core.ThreadContext)}
216: */
217: protected Object _invoke(Class callInterface, Method callMethod,
218: Method runMethod, Object[] args, Object object,
219: ThreadContext callContext) throws OpenEJBException {
220: return _invoke(callInterface, callMethod, runMethod, args,
221: (Instance) object, callContext);
222: }
223:
224: protected Object _invoke(Class callInterface, Method callMethod,
225: Method runMethod, Object[] args, Instance instance,
226: ThreadContext callContext) throws OpenEJBException {
227:
228: CoreDeploymentInfo deploymentInfo = callContext
229: .getDeploymentInfo();
230: TransactionPolicy txPolicy = deploymentInfo
231: .getTransactionPolicy(callMethod);
232: TransactionContext txContext = new TransactionContext(
233: callContext, getTransactionManager());
234: txContext.callContext = callContext;
235:
236: txPolicy.beforeInvoke(instance, txContext);
237:
238: Object returnValue = null;
239: try {
240: InterfaceType type = deploymentInfo
241: .getInterfaceType(callInterface);
242: if (type == InterfaceType.SERVICE_ENDPOINT) {
243: callContext.setCurrentOperation(Operation.BUSINESS_WS);
244: returnValue = invokeWebService(args, deploymentInfo,
245: runMethod, instance, returnValue);
246: } else {
247: List<InterceptorData> interceptors = deploymentInfo
248: .getMethodInterceptors(runMethod);
249: InterceptorStack interceptorStack = new InterceptorStack(
250: instance.bean, runMethod, Operation.BUSINESS,
251: interceptors, instance.interceptors);
252: returnValue = interceptorStack.invoke(args);
253: }
254: } catch (Throwable re) {// handle reflection exception
255: ExceptionType type = deploymentInfo.getExceptionType(re);
256: if (type == ExceptionType.SYSTEM) {
257: /* System Exception ****************************/
258:
259: /**
260: * The bean instance is not put into the pool via instanceManager.poolInstance
261: * and therefore the instance will be garbage collected and destroyed.
262: * For this reason the discardInstance method of the StatelessInstanceManager
263: * does nothing.
264: */
265:
266: txPolicy.handleSystemException(re, instance, txContext);
267: } else {
268: /* Application Exception ***********************/
269: instanceManager.poolInstance(callContext, instance);
270:
271: txPolicy.handleApplicationException(re,
272: type == ExceptionType.APPLICATION_ROLLBACK,
273: txContext);
274: }
275: } finally {
276:
277: txPolicy.afterInvoke(instance, txContext);
278: }
279:
280: return returnValue;
281: }
282:
283: private Object invokeWebService(Object[] args,
284: CoreDeploymentInfo deploymentInfo, Method runMethod,
285: Instance instance, Object returnValue) throws Exception {
286: if (args.length != 2) {
287: throw new IllegalArgumentException(
288: "WebService calls must follow format {messageContext, interceptor}.");
289: }
290:
291: Object messageContext = args[0];
292:
293: // This object will be used as an interceptor in the stack and will be responsible
294: // for unmarshalling the soap message parts into an argument list that will be
295: // used for the actual method invocation.
296: //
297: // We just need to make it an interceptor in the OpenEJB sense and tack it on the end
298: // of our stack.
299: Object interceptor = args[1];
300:
301: // Add the webservice interceptor to the list of interceptor instances
302: Map<String, Object> interceptors = new HashMap<String, Object>(
303: instance.interceptors);
304: {
305: interceptors.put(interceptor.getClass().getName(),
306: interceptor);
307: }
308:
309: // Create an InterceptorData for the webservice interceptor to the list of interceptorDatas for this method
310: List<InterceptorData> interceptorDatas = new ArrayList<InterceptorData>(
311: deploymentInfo.getMethodInterceptors(runMethod));
312: {
313: InterceptorData providerData = new InterceptorData(
314: interceptor.getClass());
315: ClassFinder finder = new ClassFinder(interceptor.getClass());
316: providerData.getAroundInvoke().addAll(
317: finder.findAnnotatedMethods(AroundInvoke.class));
318: interceptorDatas.add(providerData);
319: }
320:
321: InterceptorStack interceptorStack = new InterceptorStack(
322: instance.bean, runMethod, Operation.BUSINESS_WS,
323: interceptorDatas, interceptors);
324: Object[] params = new Object[runMethod.getParameterTypes().length];
325: if (messageContext instanceof javax.xml.rpc.handler.MessageContext) {
326: ThreadContext
327: .getThreadContext()
328: .set(
329: javax.xml.rpc.handler.MessageContext.class,
330: (javax.xml.rpc.handler.MessageContext) messageContext);
331: returnValue = interceptorStack
332: .invoke(
333: (javax.xml.rpc.handler.MessageContext) messageContext,
334: params);
335: } else if (messageContext instanceof javax.xml.ws.handler.MessageContext) {
336: ThreadContext
337: .getThreadContext()
338: .set(
339: javax.xml.ws.handler.MessageContext.class,
340: (javax.xml.ws.handler.MessageContext) messageContext);
341: returnValue = interceptorStack
342: .invoke(
343: (javax.xml.ws.handler.MessageContext) messageContext,
344: params);
345: }
346: return returnValue;
347: }
348:
349: private TransactionManager getTransactionManager() {
350: return transactionManager;
351: }
352:
353: protected ProxyInfo createEJBObject(
354: org.apache.openejb.core.CoreDeploymentInfo deploymentInfo,
355: Method callMethod) {
356: return new ProxyInfo(deploymentInfo, null);
357: }
358:
359: public void discardInstance(Object instance, ThreadContext context) {
360: instanceManager.discardInstance(context, instance);
361: }
362: }
|