KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > ejb > access > AbstractRemoteSlsbInvokerInterceptor


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.ejb.access;
18
19 import java.lang.reflect.InvocationTargetException JavaDoc;
20 import java.rmi.RemoteException JavaDoc;
21
22 import javax.ejb.EJBObject JavaDoc;
23 import javax.naming.NamingException JavaDoc;
24 import javax.rmi.PortableRemoteObject JavaDoc;
25
26 import org.aopalliance.intercept.MethodInvocation;
27
28 import org.springframework.remoting.RemoteConnectFailureException;
29 import org.springframework.remoting.RemoteLookupFailureException;
30 import org.springframework.remoting.rmi.RmiClientInterceptorUtils;
31
32 /**
33  * Superclass for interceptors proxying remote Stateless Session Beans.
34  *
35  * <p>Such an interceptor must be the last interceptor in the advice chain.
36  * In this case, there is no target object.
37  *
38  * @author Rod Johnson
39  * @author Juergen Hoeller
40  */

41 public abstract class AbstractRemoteSlsbInvokerInterceptor extends AbstractSlsbInvokerInterceptor {
42     
43     private Class JavaDoc homeInterface;
44
45     private boolean refreshHomeOnConnectFailure = false;
46
47
48     /**
49      * Set a home interface that this invoker will narrow to before performing
50      * the parameterless SLSB <code>create()</code> call that returns the actual
51      * SLSB proxy.
52      * <p>Default is none, which will work on all J2EE servers that are not based
53      * on CORBA. A plain <code>javax.ejb.EJBHome</code> interface is known to be
54      * sufficient to make a WebSphere 5.0 Remote SLSB work. On other servers,
55      * the specific home interface for the target SLSB might be necessary.
56      */

57     public void setHomeInterface(Class JavaDoc homeInterface) {
58         if (homeInterface != null && !homeInterface.isInterface()) {
59             throw new IllegalArgumentException JavaDoc(
60                     "Home interface class [" + homeInterface.getClass() + "] is not an interface");
61         }
62         this.homeInterface = homeInterface;
63     }
64
65     /**
66      * Set whether to refresh the EJB home on connect failure.
67      * Default is "false".
68      * <p>Can be turned on to allow for hot restart of the EJB server.
69      * If a cached EJB home throws an RMI exception that indicates a
70      * remote connect failure, a fresh home will be fetched and the
71      * invocation will be retried.
72      * @see java.rmi.ConnectException
73      * @see java.rmi.ConnectIOException
74      * @see java.rmi.NoSuchObjectException
75      */

76     public void setRefreshHomeOnConnectFailure(boolean refreshHomeOnConnectFailure) {
77         this.refreshHomeOnConnectFailure = refreshHomeOnConnectFailure;
78     }
79
80     protected boolean isHomeRefreshable() {
81         return this.refreshHomeOnConnectFailure;
82     }
83
84
85     /**
86      * This overridden lookup implementation performs a narrow operation
87      * after the JNDI lookup, provided that a home interface is specified.
88      * @see #setHomeInterface
89      * @see javax.rmi.PortableRemoteObject#narrow
90      */

91     protected Object JavaDoc lookup() throws NamingException JavaDoc {
92         Object JavaDoc homeObject = super.lookup();
93         if (this.homeInterface != null) {
94             try {
95                 homeObject = PortableRemoteObject.narrow(homeObject, this.homeInterface);
96             }
97             catch (ClassCastException JavaDoc ex) {
98                 throw new RemoteLookupFailureException(
99                         "Could not narrow EJB home stub to home interface [" + this.homeInterface.getName() + "]", ex);
100             }
101         }
102         return homeObject;
103     }
104
105
106     /**
107      * Fetches an EJB home object and delegates to doInvoke.
108      * If configured to refresh on connect failure, it will call
109      * refreshAndRetry on corresponding RMI exceptions.
110      * @see #getHome
111      * @see #doInvoke
112      * @see #refreshAndRetry
113      * @see java.rmi.ConnectException
114      * @see java.rmi.ConnectIOException
115      * @see java.rmi.NoSuchObjectException
116      */

117     public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
118         try {
119             return doInvoke(invocation);
120         }
121         catch (RemoteConnectFailureException ex) {
122             return handleRemoteConnectFailure(invocation, ex);
123         }
124         catch (RemoteException JavaDoc ex) {
125             if (isConnectFailure(ex)) {
126                 return handleRemoteConnectFailure(invocation, ex);
127             }
128             else {
129                 throw ex;
130             }
131         }
132     }
133
134     /**
135      * Determine whether the given RMI exception indicates a connect failure.
136      * Default implementation delegates to RmiClientInterceptorUtils.
137      * @param ex the RMI exception to check
138      * @return whether the exception should be treated as connect failure
139      * @see org.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure
140      */

141     protected boolean isConnectFailure(RemoteException JavaDoc ex) {
142         return RmiClientInterceptorUtils.isConnectFailure(ex);
143     }
144
145     private Object JavaDoc handleRemoteConnectFailure(MethodInvocation invocation, Exception JavaDoc ex) throws Throwable JavaDoc {
146         if (this.refreshHomeOnConnectFailure) {
147             if (logger.isDebugEnabled()) {
148                 logger.debug("Could not connect to remote EJB [" + getJndiName() + "] - retrying", ex);
149             }
150             else if (logger.isWarnEnabled()) {
151                 logger.warn("Could not connect to remote EJB [" + getJndiName() + "] - retrying");
152             }
153             return refreshAndRetry(invocation);
154         }
155         else {
156             throw ex;
157         }
158     }
159
160     /**
161      * Refresh the EJB home object and retry the given invocation.
162      * Called by invoke on connect failure.
163      * @param invocation the AOP method invocation
164      * @return the invocation result, if any
165      * @throws Throwable in case of invocation failure
166      * @see #invoke
167      */

168     protected Object JavaDoc refreshAndRetry(MethodInvocation invocation) throws Throwable JavaDoc {
169         try {
170             refreshHome();
171         }
172         catch (NamingException JavaDoc ex) {
173             throw new RemoteLookupFailureException("Failed to locate remote EJB [" + getJndiName() + "]", ex);
174         }
175         return doInvoke(invocation);
176     }
177
178
179     /**
180      * Perform the given invocation on the current EJB home.
181      * Template method to be implemented by a subclass.
182      * @param invocation the AOP method invocation
183      * @return the invocation result, if any
184      * @throws Throwable in case of invocation failure
185      * @see #getHome
186      * @see #newSessionBeanInstance
187      */

188     protected abstract Object JavaDoc doInvoke(MethodInvocation invocation) throws Throwable JavaDoc;
189
190
191     /**
192      * Return a new instance of the stateless session bean.
193      * To be invoked by concrete remote SLSB invoker subclasses.
194      * <p>Can be overridden to change the algorithm.
195      * @throws NamingException if thrown by JNDI
196      * @throws InvocationTargetException if thrown by the create method
197      * @see #create
198      */

199     protected EJBObject JavaDoc newSessionBeanInstance() throws NamingException JavaDoc, InvocationTargetException JavaDoc {
200         if (logger.isDebugEnabled()) {
201             logger.debug("Trying to create reference to remote EJB");
202         }
203
204         // invoke the superclass' generic create method
205
Object JavaDoc ejbInstance = create();
206         if (!(ejbInstance instanceof EJBObject JavaDoc)) {
207             throw new RemoteLookupFailureException(
208                     "EJB instance [" + ejbInstance + "] is not a Remote Stateless Session Bean");
209         }
210         // if it throws remote exception (wrapped in InvocationTargetException), retry?
211

212         if (logger.isDebugEnabled()) {
213             logger.debug("Obtained reference to remote EJB: " + ejbInstance);
214         }
215         return (EJBObject JavaDoc) ejbInstance;
216     }
217
218     /**
219      * Remove the given EJB instance.
220      * To be invoked by concrete remote SLSB invoker subclasses.
221      * @param ejb the EJB instance to remove
222      * @see javax.ejb.EJBObject#remove
223      */

224     protected void removeSessionBeanInstance(EJBObject JavaDoc ejb) {
225         if (ejb != null) {
226             try {
227                 ejb.remove();
228             }
229             catch (Throwable JavaDoc ex) {
230                 logger.warn("Could not invoke 'remove' on remote EJB proxy", ex);
231             }
232         }
233     }
234
235 }
236
Popular Tags