001: /*
002: * Copyright 2007 The Kuali Foundation
003: *
004: * Licensed under the Educational Community License, Version 1.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.opensource.org/licenses/ecl1.php
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: package edu.iu.uis.eden.messaging;
017:
018: import java.io.InterruptedIOException;
019: import java.lang.reflect.Method;
020: import java.lang.reflect.Proxy;
021: import java.net.ConnectException;
022: import java.net.NoRouteToHostException;
023: import java.net.UnknownHostException;
024: import java.util.ArrayList;
025: import java.util.List;
026:
027: import org.apache.commons.httpclient.ConnectTimeoutException;
028: import org.apache.commons.httpclient.ConnectionPoolTimeoutException;
029: import org.apache.commons.httpclient.NoHttpResponseException;
030: import org.apache.log4j.Logger;
031: import org.kuali.rice.proxy.BaseTargetedInvocationHandler;
032: import org.kuali.rice.resourceloader.ContextClassLoaderProxy;
033: import org.kuali.rice.util.ClassLoaderUtils;
034:
035: import edu.iu.uis.eden.messaging.resourceloading.KSBResourceLoaderFactory;
036:
037: public class BusClientFailureProxy extends
038: BaseTargetedInvocationHandler {
039:
040: private static final Logger LOG = Logger
041: .getLogger(BusClientFailureProxy.class);
042:
043: private ServiceInfo serviceInfo;
044:
045: // exceptions that will cause this Proxy to remove the service from the bus
046: private static List<Class> serviceRemovalExceptions = new ArrayList<Class>();
047:
048: static {
049: serviceRemovalExceptions.add(NoHttpResponseException.class);
050: serviceRemovalExceptions.add(InterruptedIOException.class);
051: serviceRemovalExceptions.add(UnknownHostException.class);
052: serviceRemovalExceptions.add(NoRouteToHostException.class);
053: serviceRemovalExceptions.add(ConnectTimeoutException.class);
054: serviceRemovalExceptions
055: .add(ConnectionPoolTimeoutException.class);
056: serviceRemovalExceptions.add(ConnectException.class);
057: }
058:
059: private BusClientFailureProxy(Object target, ServiceInfo serviceInfo) {
060: super (target);
061: this .serviceInfo = serviceInfo;
062: }
063:
064: public static Object wrap(Object target, ServiceInfo serviceInfo) {
065: return Proxy.newProxyInstance(ClassLoaderUtils
066: .getDefaultClassLoader(), ContextClassLoaderProxy
067: .getInterfacesToProxyIncludeSpring(target),
068: new BusClientFailureProxy(target, serviceInfo));
069: }
070:
071: protected Object invokeInternal(Object proxyObject, Method method,
072: Object[] params) throws Throwable {
073: try {
074: return method.invoke(getTarget(), params);
075: } catch (Throwable throwable) {
076: if (isServiceRemovalException(throwable)) {
077: LOG.error("Exception caught accessing remote service "
078: + this .serviceInfo.getQname(), throwable);
079: RemoteResourceServiceLocator remoteResourceLocator = KSBResourceLoaderFactory
080: .getRemoteResourceLocator();
081: remoteResourceLocator.removeService(this .serviceInfo,
082: proxyObject);
083:
084: Object service = remoteResourceLocator
085: .getService(this .serviceInfo.getQname());
086: if (service != null) {
087: LOG
088: .info("Refetched replacement service for service "
089: + this .serviceInfo.getQname());
090: return method.invoke(service, params);
091: }
092: LOG
093: .error("Didn't find replacement service throwing exception");
094: }
095: throw throwable;
096: }
097: }
098:
099: private static boolean isServiceRemovalException(Throwable throwable) {
100: LOG.info("Checking for Service Removal Exception: "
101: + throwable.getClass().getName());
102: if (serviceRemovalExceptions.contains(throwable.getClass())) {
103: LOG.info("Found a Service Removal Exception: "
104: + throwable.getClass().getName());
105: return true;
106: } else if (throwable instanceof HttpException) {
107: HttpException httpException = (HttpException) throwable;
108: if (httpException.getResponseCode() == 503) {
109: LOG
110: .info("Found a Service Removal Exception because of a 503: "
111: + throwable.getClass().getName());
112: return true;
113: }
114: }
115: if (throwable.getCause() != null) {
116: LOG
117: .info("Unwrapping Throwable cause to check for service removal exception from: "
118: + throwable.getClass().getName());
119: return isServiceRemovalException(throwable.getCause());
120: }
121: return false;
122: }
123: }
|