Source Code Cross Referenced for JndiRmiClientInterceptor.java in  » J2EE » spring-framework-2.5 » org » springframework » remoting » rmi » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.5 » org.springframework.remoting.rmi 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2002-2007 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.remoting.rmi;
018:
019:        import java.lang.reflect.InvocationTargetException;
020:        import java.lang.reflect.Method;
021:        import java.rmi.Remote;
022:        import java.rmi.RemoteException;
023:
024:        import javax.naming.NamingException;
025:        import javax.rmi.PortableRemoteObject;
026:
027:        import org.aopalliance.intercept.MethodInterceptor;
028:        import org.aopalliance.intercept.MethodInvocation;
029:        import org.omg.CORBA.OBJECT_NOT_EXIST;
030:        import org.omg.CORBA.SystemException;
031:
032:        import org.springframework.aop.support.AopUtils;
033:        import org.springframework.beans.factory.InitializingBean;
034:        import org.springframework.jndi.JndiObjectLocator;
035:        import org.springframework.remoting.RemoteAccessException;
036:        import org.springframework.remoting.RemoteConnectFailureException;
037:        import org.springframework.remoting.RemoteInvocationFailureException;
038:        import org.springframework.remoting.RemoteLookupFailureException;
039:        import org.springframework.remoting.support.DefaultRemoteInvocationFactory;
040:        import org.springframework.remoting.support.RemoteInvocation;
041:        import org.springframework.remoting.support.RemoteInvocationFactory;
042:        import org.springframework.util.ReflectionUtils;
043:
044:        /**
045:         * {@link org.aopalliance.intercept.MethodInterceptor} for accessing RMI services from JNDI.
046:         * Typically used for RMI-IIOP (CORBA), but can also be used for EJB home objects
047:         * (for example, a Stateful Session Bean home). In contrast to a plain JNDI lookup,
048:         * this accessor also performs narrowing through PortableRemoteObject.
049:         *
050:         * <p>With conventional RMI services, this invoker is typically used with the RMI
051:         * service interface. Alternatively, this invoker can also proxy a remote RMI service
052:         * with a matching non-RMI business interface, i.e. an interface that mirrors the RMI
053:         * service methods but does not declare RemoteExceptions. In the latter case,
054:         * RemoteExceptions thrown by the RMI stub will automatically get converted to
055:         * Spring's unchecked RemoteAccessException.
056:         *
057:         * <p>The JNDI environment can be specified as "jndiEnvironment" property,
058:         * or be configured in a <code>jndi.properties</code> file or as system properties.
059:         * For example:
060:         *
061:         * <pre class="code">&lt;property name="jndiEnvironment"&gt;
062:         * 	 &lt;props>
063:         *		 &lt;prop key="java.naming.factory.initial"&gt;com.sun.jndi.cosnaming.CNCtxFactory&lt;/prop&gt;
064:         *		 &lt;prop key="java.naming.provider.url"&gt;iiop://localhost:1050&lt;/prop&gt;
065:         *	 &lt;/props&gt;
066:         * &lt;/property&gt;</pre>
067:         *
068:         * @author Juergen Hoeller
069:         * @since 1.1
070:         * @see #setJndiTemplate
071:         * @see #setJndiEnvironment
072:         * @see #setJndiName
073:         * @see JndiRmiServiceExporter
074:         * @see JndiRmiProxyFactoryBean
075:         * @see org.springframework.remoting.RemoteAccessException
076:         * @see java.rmi.RemoteException
077:         * @see java.rmi.Remote
078:         * @see javax.rmi.PortableRemoteObject#narrow
079:         */
080:        public class JndiRmiClientInterceptor extends JndiObjectLocator
081:                implements  MethodInterceptor, InitializingBean {
082:
083:            private Class serviceInterface;
084:
085:            private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory();
086:
087:            private boolean lookupStubOnStartup = true;
088:
089:            private boolean cacheStub = true;
090:
091:            private boolean refreshStubOnConnectFailure = false;
092:
093:            private Remote cachedStub;
094:
095:            private final Object stubMonitor = new Object();
096:
097:            /**
098:             * Set the interface of the service to access.
099:             * The interface must be suitable for the particular service and remoting tool.
100:             * <p>Typically required to be able to create a suitable service proxy,
101:             * but can also be optional if the lookup returns a typed stub.
102:             */
103:            public void setServiceInterface(Class serviceInterface) {
104:                if (serviceInterface != null && !serviceInterface.isInterface()) {
105:                    throw new IllegalArgumentException(
106:                            "'serviceInterface' must be an interface");
107:                }
108:                this .serviceInterface = serviceInterface;
109:            }
110:
111:            /**
112:             * Return the interface of the service to access.
113:             */
114:            public Class getServiceInterface() {
115:                return this .serviceInterface;
116:            }
117:
118:            /**
119:             * Set the RemoteInvocationFactory to use for this accessor.
120:             * Default is a {@link DefaultRemoteInvocationFactory}.
121:             * <p>A custom invocation factory can add further context information
122:             * to the invocation, for example user credentials.
123:             */
124:            public void setRemoteInvocationFactory(
125:                    RemoteInvocationFactory remoteInvocationFactory) {
126:                this .remoteInvocationFactory = remoteInvocationFactory;
127:            }
128:
129:            /**
130:             * Return the RemoteInvocationFactory used by this accessor.
131:             */
132:            public RemoteInvocationFactory getRemoteInvocationFactory() {
133:                return this .remoteInvocationFactory;
134:            }
135:
136:            /**
137:             * Set whether to look up the RMI stub on startup. Default is "true".
138:             * <p>Can be turned off to allow for late start of the RMI server.
139:             * In this case, the RMI stub will be fetched on first access.
140:             * @see #setCacheStub
141:             */
142:            public void setLookupStubOnStartup(boolean lookupStubOnStartup) {
143:                this .lookupStubOnStartup = lookupStubOnStartup;
144:            }
145:
146:            /**
147:             * Set whether to cache the RMI stub once it has been located.
148:             * Default is "true".
149:             * <p>Can be turned off to allow for hot restart of the RMI server.
150:             * In this case, the RMI stub will be fetched for each invocation.
151:             * @see #setLookupStubOnStartup
152:             */
153:            public void setCacheStub(boolean cacheStub) {
154:                this .cacheStub = cacheStub;
155:            }
156:
157:            /**
158:             * Set whether to refresh the RMI stub on connect failure.
159:             * Default is "false".
160:             * <p>Can be turned on to allow for hot restart of the RMI server.
161:             * If a cached RMI stub throws an RMI exception that indicates a
162:             * remote connect failure, a fresh proxy will be fetched and the
163:             * invocation will be retried.
164:             * @see java.rmi.ConnectException
165:             * @see java.rmi.ConnectIOException
166:             * @see java.rmi.NoSuchObjectException
167:             */
168:            public void setRefreshStubOnConnectFailure(
169:                    boolean refreshStubOnConnectFailure) {
170:                this .refreshStubOnConnectFailure = refreshStubOnConnectFailure;
171:            }
172:
173:            public void afterPropertiesSet() throws NamingException {
174:                super .afterPropertiesSet();
175:                prepare();
176:            }
177:
178:            /**
179:             * Fetches the RMI stub on startup, if necessary.
180:             * @throws RemoteLookupFailureException if RMI stub creation failed
181:             * @see #setLookupStubOnStartup
182:             * @see #lookupStub
183:             */
184:            public void prepare() throws RemoteLookupFailureException {
185:                // Cache RMI stub on initialization?
186:                if (this .lookupStubOnStartup) {
187:                    Remote remoteObj = lookupStub();
188:                    if (logger.isDebugEnabled()) {
189:                        if (remoteObj instanceof  RmiInvocationHandler) {
190:                            logger.debug("JNDI RMI object [" + getJndiName()
191:                                    + "] is an RMI invoker");
192:                        } else if (getServiceInterface() != null) {
193:                            boolean isImpl = getServiceInterface().isInstance(
194:                                    remoteObj);
195:                            logger.debug("Using service interface ["
196:                                    + getServiceInterface().getName()
197:                                    + "] for JNDI RMI object [" + getJndiName()
198:                                    + "] - " + (!isImpl ? "not " : "")
199:                                    + "directly implemented");
200:                        }
201:                    }
202:                    if (this .cacheStub) {
203:                        this .cachedStub = remoteObj;
204:                    }
205:                }
206:            }
207:
208:            /**
209:             * Create the RMI stub, typically by looking it up.
210:             * <p>Called on interceptor initialization if "cacheStub" is "true";
211:             * else called for each invocation by {@link #getStub()}.
212:             * <p>The default implementation retrieves the service from the
213:             * JNDI environment. This can be overridden in subclasses.
214:             * @return the RMI stub to store in this interceptor
215:             * @throws RemoteLookupFailureException if RMI stub creation failed
216:             * @see #setCacheStub
217:             * @see #lookup
218:             */
219:            protected Remote lookupStub() throws RemoteLookupFailureException {
220:                try {
221:                    Object stub = lookup();
222:                    if (getServiceInterface() != null
223:                            && Remote.class
224:                                    .isAssignableFrom(getServiceInterface())) {
225:                        try {
226:                            stub = PortableRemoteObject.narrow(stub,
227:                                    getServiceInterface());
228:                        } catch (ClassCastException ex) {
229:                            throw new RemoteLookupFailureException(
230:                                    "Could not narrow RMI stub to service interface ["
231:                                            + getServiceInterface().getName()
232:                                            + "]", ex);
233:                        }
234:                    }
235:                    if (!(stub instanceof  Remote)) {
236:                        throw new RemoteLookupFailureException(
237:                                "Located RMI stub of class ["
238:                                        + stub.getClass().getName()
239:                                        + "], with JNDI name ["
240:                                        + getJndiName()
241:                                        + "], does not implement interface [java.rmi.Remote]");
242:                    }
243:                    return (Remote) stub;
244:                } catch (NamingException ex) {
245:                    throw new RemoteLookupFailureException(
246:                            "JNDI lookup for RMI service [" + getJndiName()
247:                                    + "] failed", ex);
248:                }
249:            }
250:
251:            /**
252:             * Return the RMI stub to use. Called for each invocation.
253:             * <p>The default implementation returns the stub created on initialization,
254:             * if any. Else, it invokes {@link #lookupStub} to get a new stub for
255:             * each invocation. This can be overridden in subclasses, for example in
256:             * order to cache a stub for a given amount of time before recreating it,
257:             * or to test the stub whether it is still alive.
258:             * @return the RMI stub to use for an invocation
259:             * @throws NamingException if stub creation failed
260:             * @throws RemoteLookupFailureException if RMI stub creation failed
261:             */
262:            protected Remote getStub() throws NamingException,
263:                    RemoteLookupFailureException {
264:                if (!this .cacheStub
265:                        || (this .lookupStubOnStartup && !this .refreshStubOnConnectFailure)) {
266:                    return (this .cachedStub != null ? this .cachedStub
267:                            : lookupStub());
268:                } else {
269:                    synchronized (this .stubMonitor) {
270:                        if (this .cachedStub == null) {
271:                            this .cachedStub = lookupStub();
272:                        }
273:                        return this .cachedStub;
274:                    }
275:                }
276:            }
277:
278:            /**
279:             * Fetches an RMI stub and delegates to {@link #doInvoke}.
280:             * If configured to refresh on connect failure, it will call
281:             * {@link #refreshAndRetry} on corresponding RMI exceptions.
282:             * @see #getStub
283:             * @see #doInvoke
284:             * @see #refreshAndRetry
285:             * @see java.rmi.ConnectException
286:             * @see java.rmi.ConnectIOException
287:             * @see java.rmi.NoSuchObjectException
288:             */
289:            public Object invoke(MethodInvocation invocation) throws Throwable {
290:                Remote stub = null;
291:                try {
292:                    stub = getStub();
293:                } catch (NamingException ex) {
294:                    throw new RemoteLookupFailureException(
295:                            "JNDI lookup for RMI service [" + getJndiName()
296:                                    + "] failed", ex);
297:                }
298:                try {
299:                    return doInvoke(invocation, stub);
300:                } catch (RemoteConnectFailureException ex) {
301:                    return handleRemoteConnectFailure(invocation, ex);
302:                } catch (RemoteException ex) {
303:                    if (isConnectFailure(ex)) {
304:                        return handleRemoteConnectFailure(invocation, ex);
305:                    } else {
306:                        throw ex;
307:                    }
308:                } catch (SystemException ex) {
309:                    if (isConnectFailure(ex)) {
310:                        return handleRemoteConnectFailure(invocation, ex);
311:                    } else {
312:                        throw ex;
313:                    }
314:                }
315:            }
316:
317:            /**
318:             * Determine whether the given RMI exception indicates a connect failure.
319:             * <p>The default implementation delegates to
320:             * {@link RmiClientInterceptorUtils#isConnectFailure}.
321:             * @param ex the RMI exception to check
322:             * @return whether the exception should be treated as connect failure
323:             */
324:            protected boolean isConnectFailure(RemoteException ex) {
325:                return RmiClientInterceptorUtils.isConnectFailure(ex);
326:            }
327:
328:            /**
329:             * Determine whether the given CORBA exception indicates a connect failure.
330:             * <p>The default implementation checks for CORBA's
331:             * {@link org.omg.CORBA.OBJECT_NOT_EXIST} exception.
332:             * @param ex the RMI exception to check
333:             * @return whether the exception should be treated as connect failure
334:             */
335:            protected boolean isConnectFailure(SystemException ex) {
336:                return (ex instanceof  OBJECT_NOT_EXIST);
337:            }
338:
339:            /**
340:             * Refresh the stub and retry the remote invocation if necessary.
341:             * <p>If not configured to refresh on connect failure, this method
342:             * simply rethrows the original exception.
343:             * @param invocation the invocation that failed
344:             * @param ex the exception raised on remote invocation
345:             * @return the result value of the new invocation, if succeeded
346:             * @throws Throwable an exception raised by the new invocation, if failed too.
347:             */
348:            private Object handleRemoteConnectFailure(
349:                    MethodInvocation invocation, Exception ex) throws Throwable {
350:                if (this .refreshStubOnConnectFailure) {
351:                    if (logger.isDebugEnabled()) {
352:                        logger.debug("Could not connect to RMI service ["
353:                                + getJndiName() + "] - retrying", ex);
354:                    } else if (logger.isWarnEnabled()) {
355:                        logger.warn("Could not connect to RMI service ["
356:                                + getJndiName() + "] - retrying");
357:                    }
358:                    return refreshAndRetry(invocation);
359:                } else {
360:                    throw ex;
361:                }
362:            }
363:
364:            /**
365:             * Refresh the RMI stub and retry the given invocation.
366:             * Called by invoke on connect failure.
367:             * @param invocation the AOP method invocation
368:             * @return the invocation result, if any
369:             * @throws Throwable in case of invocation failure
370:             * @see #invoke
371:             */
372:            protected Object refreshAndRetry(MethodInvocation invocation)
373:                    throws Throwable {
374:                Remote freshStub = null;
375:                synchronized (this .stubMonitor) {
376:                    this .cachedStub = null;
377:                    freshStub = lookupStub();
378:                    if (this .cacheStub) {
379:                        this .cachedStub = freshStub;
380:                    }
381:                }
382:                return doInvoke(invocation, freshStub);
383:            }
384:
385:            /**
386:             * Perform the given invocation on the given RMI stub.
387:             * @param invocation the AOP method invocation
388:             * @param stub the RMI stub to invoke
389:             * @return the invocation result, if any
390:             * @throws Throwable in case of invocation failure
391:             */
392:            protected Object doInvoke(MethodInvocation invocation, Remote stub)
393:                    throws Throwable {
394:                if (stub instanceof  RmiInvocationHandler) {
395:                    // RMI invoker
396:                    try {
397:                        return doInvoke(invocation, (RmiInvocationHandler) stub);
398:                    } catch (RemoteException ex) {
399:                        throw convertRmiAccessException(ex, invocation
400:                                .getMethod());
401:                    } catch (SystemException ex) {
402:                        throw convertCorbaAccessException(ex, invocation
403:                                .getMethod());
404:                    } catch (InvocationTargetException ex) {
405:                        throw ex.getTargetException();
406:                    } catch (Throwable ex) {
407:                        throw new RemoteInvocationFailureException(
408:                                "Invocation of method ["
409:                                        + invocation.getMethod()
410:                                        + "] failed in RMI service ["
411:                                        + getJndiName() + "]", ex);
412:                    }
413:                } else {
414:                    // traditional RMI stub
415:                    try {
416:                        return RmiClientInterceptorUtils.doInvoke(invocation,
417:                                stub);
418:                    } catch (InvocationTargetException ex) {
419:                        Throwable targetEx = ex.getTargetException();
420:                        if (targetEx instanceof  RemoteException) {
421:                            throw convertRmiAccessException(
422:                                    (RemoteException) targetEx, invocation
423:                                            .getMethod());
424:                        } else if (targetEx instanceof  SystemException) {
425:                            throw convertCorbaAccessException(
426:                                    (SystemException) targetEx, invocation
427:                                            .getMethod());
428:                        } else {
429:                            throw targetEx;
430:                        }
431:                    }
432:                }
433:            }
434:
435:            /**
436:             * Apply the given AOP method invocation to the given {@link RmiInvocationHandler}.
437:             * <p>The default implementation delegates to {@link #createRemoteInvocation}.
438:             * @param methodInvocation the current AOP method invocation
439:             * @param invocationHandler the RmiInvocationHandler to apply the invocation to
440:             * @return the invocation result
441:             * @throws RemoteException in case of communication errors
442:             * @throws NoSuchMethodException if the method name could not be resolved
443:             * @throws IllegalAccessException if the method could not be accessed
444:             * @throws InvocationTargetException if the method invocation resulted in an exception
445:             * @see org.springframework.remoting.support.RemoteInvocation
446:             */
447:            protected Object doInvoke(MethodInvocation methodInvocation,
448:                    RmiInvocationHandler invocationHandler)
449:                    throws RemoteException, NoSuchMethodException,
450:                    IllegalAccessException, InvocationTargetException {
451:
452:                if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
453:                    return "RMI invoker proxy for service URL ["
454:                            + getJndiName() + "]";
455:                }
456:
457:                return invocationHandler
458:                        .invoke(createRemoteInvocation(methodInvocation));
459:            }
460:
461:            /**
462:             * Create a new RemoteInvocation object for the given AOP method invocation.
463:             * <p>The default implementation delegates to the configured
464:             * {@link #setRemoteInvocationFactory RemoteInvocationFactory}.
465:             * This can be overridden in subclasses in order to provide custom RemoteInvocation
466:             * subclasses, containing additional invocation parameters (e.g. user credentials).
467:             * <p>Note that it is preferable to build a custom RemoteInvocationFactory
468:             * as a reusable strategy, instead of overriding this method.
469:             * @param methodInvocation the current AOP method invocation
470:             * @return the RemoteInvocation object
471:             * @see RemoteInvocationFactory#createRemoteInvocation
472:             */
473:            protected RemoteInvocation createRemoteInvocation(
474:                    MethodInvocation methodInvocation) {
475:                return getRemoteInvocationFactory().createRemoteInvocation(
476:                        methodInvocation);
477:            }
478:
479:            /**
480:             * Convert the given RMI RemoteException that happened during remote access
481:             * to Spring's RemoteAccessException if the method signature does not declare
482:             * RemoteException. Else, return the original RemoteException.
483:             * @param method the invoked method
484:             * @param ex the RemoteException that happened
485:             * @return the exception to be thrown to the caller
486:             */
487:            private Exception convertRmiAccessException(RemoteException ex,
488:                    Method method) {
489:                return RmiClientInterceptorUtils.convertRmiAccessException(
490:                        method, ex, isConnectFailure(ex), getJndiName());
491:            }
492:
493:            /**
494:             * Convert the given CORBA SystemException that happened during remote access
495:             * to Spring's RemoteAccessException if the method signature does not declare
496:             * RemoteException. Else, return the SystemException wrapped in a RemoteException.
497:             * @param method the invoked method
498:             * @param ex the RemoteException that happened
499:             * @return the exception to be thrown to the caller
500:             */
501:            private Exception convertCorbaAccessException(SystemException ex,
502:                    Method method) {
503:                if (ReflectionUtils.declaresException(method,
504:                        RemoteException.class)) {
505:                    // A traditional RMI service: wrap CORBA exceptions in standard RemoteExceptions.
506:                    return new RemoteException(
507:                            "Failed to access CORBA service [" + getJndiName()
508:                                    + "]", ex);
509:                } else {
510:                    if (isConnectFailure(ex)) {
511:                        return new RemoteConnectFailureException(
512:                                "Could not connect to CORBA service ["
513:                                        + getJndiName() + "]", ex);
514:                    } else {
515:                        return new RemoteAccessException(
516:                                "Could not access CORBA service ["
517:                                        + getJndiName() + "]", ex);
518:                    }
519:                }
520:            }
521:
522:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.