/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.coordinator.client.service.impl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.rmi.RemoteException; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.remoting.RemoteLookupFailureException; import org.springframework.remoting.rmi.RmiProxyFactoryBean; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.coordinator.common.Service; import com.emc.storageos.coordinator.exceptions.CoordinatorException; /** * Invocation handler implementation for RMI endpoints. This implementation fails over * (if more than one endpoint is available) on connection failure. */ public class RmiInvocationHandler implements InvocationHandler { private static final Logger _log = LoggerFactory.getLogger(RmiInvocationHandler.class); private CoordinatorClient _client; private String _name, _version, _tag, _endpointKey; private Class _endpointInterface; private final ConcurrentMap<URI, Object> _proxyMap = new ConcurrentHashMap<URI, Object>(); public void setCoordinator(CoordinatorClient client) { _client = client; } public void setName(String name) { _name = name; } public void setVersion(String version) { _version = version; } public void setTag(String tag) { _tag = tag; } public void setEndpointInterface(Class endpointInterface) { _endpointInterface = endpointInterface; } public void setEndpointKey(String endpointKey) { _endpointKey = endpointKey; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { List<Service> services = _client.locateAllServices(_name, _version, _tag, _endpointKey); if (services == null || services.isEmpty()) { throw CoordinatorException.fatals.endPointUnavailable(); } _log.info("Invoking task {}: {} ", method, args); Throwable lastError = null; for (int index = 0; index < services.size(); index++) { Service svc = services.get(index); URI endpoint = null; if (_endpointKey != null) { endpoint = svc.getEndpoint(_endpointKey); } else { endpoint = svc.getEndpoint(); } Object rmiProxy = _proxyMap.get(endpoint); try { if (rmiProxy == null) { rmiProxy = createRmiProxy(endpoint); } _log.info("Sending RMI request to {} ", endpoint); return method.invoke(rmiProxy, args); } catch (RemoteLookupFailureException e) { lastError = e; _log.warn("Unable to lookup registry at {}", endpoint); continue; } catch (InvocationTargetException e) { Throwable target = e.getTargetException(); if (target instanceof RemoteException || target instanceof RemoteLookupFailureException) { // fail over to next host lastError = target; _log.warn("Remote exception trying to reach {}", endpoint, target); continue; } throw target; } } throw CoordinatorException.fatals.unableToConnectToEndpoint(lastError); } /** * Creates and caches RMI proxy * * @param endpoint * @return */ private Object createRmiProxy(URI endpoint) { RmiProxyFactoryBean proxyFactory = new RmiProxyFactoryBean(); proxyFactory.setServiceInterface(_endpointInterface); proxyFactory.setServiceUrl(endpoint.toString()); proxyFactory.setRefreshStubOnConnectFailure(true); proxyFactory.setCacheStub(false); proxyFactory.afterPropertiesSet(); Object rmiProxy = proxyFactory.getObject(); _proxyMap.putIfAbsent(endpoint, rmiProxy); return rmiProxy; } }