001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.ejb.access;
018:
019: import java.lang.reflect.InvocationTargetException;
020: import java.rmi.RemoteException;
021:
022: import javax.ejb.CreateException;
023: import javax.ejb.EJBObject;
024: import javax.naming.NamingException;
025:
026: import org.aopalliance.intercept.MethodInvocation;
027:
028: import org.springframework.remoting.RemoteLookupFailureException;
029: import org.springframework.remoting.rmi.RmiClientInterceptorUtils;
030:
031: /**
032: * <p>Basic invoker for a remote Stateless Session Bean.
033: * "Creates" a new EJB instance for each invocation.
034: *
035: * <p>See {@link org.springframework.jndi.JndiObjectLocator} for info on
036: * how to specify the JNDI location of the target EJB.
037: *
038: * <p>In a bean container, this class is normally best used as a singleton. However,
039: * if that bean container pre-instantiates singletons (as do the XML ApplicationContext
040: * variants) you may have a problem if the bean container is loaded before the EJB
041: * container loads the target EJB. That is because by default the JNDI lookup will be
042: * performed in the init method of this class and cached, but the EJB will not have been
043: * bound at the target location yet. The best solution is to set the lookupHomeOnStartup
044: * property to false, in which case the home will be fetched on first access to the EJB.
045: * (This flag is only true by default for backwards compatibility reasons).</p>
046: *
047: * <p>This invoker is typically used with an RMI business interface, which serves
048: * as super-interface of the EJB component interface. Alternatively, this invoker
049: * can also proxy a remote SLSB with a matching non-RMI business interface, i.e. an
050: * interface that mirrors the EJB business methods but does not declare RemoteExceptions.
051: * In the latter case, RemoteExceptions thrown by the EJB stub will automatically get
052: * converted to Spring's unchecked RemoteAccessException.
053: *
054: * @author Rod Johnson
055: * @author Juergen Hoeller
056: * @since 09.05.2003
057: * @see org.springframework.remoting.RemoteAccessException
058: * @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
059: * @see AbstractSlsbInvokerInterceptor#setCacheHome
060: * @see AbstractRemoteSlsbInvokerInterceptor#setRefreshHomeOnConnectFailure
061: */
062: public class SimpleRemoteSlsbInvokerInterceptor extends
063: AbstractRemoteSlsbInvokerInterceptor {
064:
065: /**
066: * This implementation "creates" a new EJB instance for each invocation.
067: * Can be overridden for custom invocation strategies.
068: * <p>Alternatively, override getSessionBeanInstance and
069: * releaseSessionBeanInstance to change EJB instance creation,
070: * for example to hold a single shared EJB instance.
071: */
072: protected Object doInvoke(MethodInvocation invocation)
073: throws Throwable {
074: EJBObject ejb = null;
075: try {
076: ejb = getSessionBeanInstance();
077: return RmiClientInterceptorUtils.doInvoke(invocation, ejb);
078: } catch (NamingException ex) {
079: throw new RemoteLookupFailureException(
080: "Failed to locate remote EJB [" + getJndiName()
081: + "]", ex);
082: } catch (InvocationTargetException ex) {
083: Throwable targetEx = ex.getTargetException();
084: if (targetEx instanceof RemoteException) {
085: RemoteException rex = (RemoteException) targetEx;
086: throw RmiClientInterceptorUtils
087: .convertRmiAccessException(invocation
088: .getMethod(), rex,
089: isConnectFailure(rex), getJndiName());
090: } else if (targetEx instanceof CreateException) {
091: throw RmiClientInterceptorUtils
092: .convertRmiAccessException(invocation
093: .getMethod(), targetEx,
094: "Could not create remote EJB ["
095: + getJndiName() + "]");
096: }
097: throw targetEx;
098: } finally {
099: if (ejb != null) {
100: releaseSessionBeanInstance(ejb);
101: }
102: }
103: }
104:
105: /**
106: * Return an EJB instance to delegate the call to.
107: * Default implementation delegates to newSessionBeanInstance.
108: * @throws NamingException if thrown by JNDI
109: * @throws InvocationTargetException if thrown by the create method
110: * @see #newSessionBeanInstance
111: */
112: protected EJBObject getSessionBeanInstance()
113: throws NamingException, InvocationTargetException {
114: return newSessionBeanInstance();
115: }
116:
117: /**
118: * Release the given EJB instance.
119: * Default implementation delegates to removeSessionBeanInstance.
120: * @param ejb the EJB instance to release
121: * @see #removeSessionBeanInstance
122: */
123: protected void releaseSessionBeanInstance(EJBObject ejb) {
124: removeSessionBeanInstance(ejb);
125: }
126:
127: }
|