package org.ovirt.engine.core.vdsbroker.xmlrpc; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory; import org.apache.xmlrpc.client.util.ClientFactory; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.compat.KeyValuePairCompat; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.utils.ssl.AuthSSLProtocolSocketFactory; import org.ovirt.engine.core.utils.threadpool.ThreadPoolUtil; public class XmlRpcUtils { private static final String HTTP = "http://"; private static final String HTTPS = "https://"; private static LogCompat log = LogFactoryCompat.getLog(XmlRpcUtils.class); static { if (Config.<Boolean> GetValue(ConfigValues.UseSecureConnectionWithServers)) { URL keystoreUrl; try { keystoreUrl = new URL("file://" + Config.resolveKeyStorePath()); String keystorePassword = Config.<String> GetValue(ConfigValues.keystorePass); URL truststoreUrl = new URL("file://" + Config.resolveTrustStorePath()); String truststorePassword = Config.<String> GetValue(ConfigValues.TruststorePass); // registering the https protocol with a socket factory that // provides client authentication. ProtocolSocketFactory factory = new AuthSSLProtocolSocketFactory(keystoreUrl, keystorePassword, truststoreUrl, truststorePassword); Protocol clientAuthHTTPS = new Protocol("https", factory, 54321); Protocol.registerProtocol("https", clientAuthHTTPS); } catch (Exception e) { log.fatal("Failed to init AuthSSLProtocolSocketFactory. SSL connections will not work", e); } } } /** * wrapper for the apache xmlrpc client factory. gets the xmlrpc connection parameters and an interface to implement * and returns an instance which implements the given interface. * @param <T> * the type of the instance for the interface * @param hostName * - the host to connect to * @param port * - the port to connect to * @param clientTimeOut * - the time out for the connection * @param type * - the instance type of the interface for this connection * @param isSecure * - if a connection should be https or http * @return an instance of the given type. */ public static <T> KeyValuePairCompat<T, HttpClient> getConnection(String hostName, int port, int clientTimeOut, Class<T> type, boolean isSecure) { URL serverUrl; String prefix; if (isSecure) { prefix = HTTPS; } else { prefix = HTTP; } try { serverUrl = new URL(prefix + hostName + ":" + port); } catch (MalformedURLException mfue) { log.error("failed to forme the xml-rpc url", mfue); return null; } return getHttpConnection(serverUrl, clientTimeOut, type); } public static void shutDownConnection(HttpClient httpClient) { if (httpClient != null && httpClient.getHttpConnectionManager() != null) { ((MultiThreadedHttpConnectionManager) (httpClient).getHttpConnectionManager()).shutdown(); } } @SuppressWarnings("unchecked") private static <T> KeyValuePairCompat<T, HttpClient> getHttpConnection(URL serverUrl, int clientTimeOut, Class<T> type) { XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); config.setServerURL(serverUrl); config.setConnectionTimeout(clientTimeOut); config.setReplyTimeout(clientTimeOut); XmlRpcClient xmlRpcClient = new XmlRpcClient(); xmlRpcClient.setConfig(config); XmlRpcCommonsTransportFactory transportFactory = new XmlRpcCommonsTransportFactory(xmlRpcClient); HttpClient httpclient = new HttpClient(new MultiThreadedHttpConnectionManager()); transportFactory.setHttpClient(httpclient); xmlRpcClient.setTransportFactory(transportFactory); ClientFactory clientFactory = new ClientFactory(xmlRpcClient); T connector = (T) clientFactory.newInstance(Thread.currentThread().getContextClassLoader(), type, null); T asyncConnector = (T) AsyncProxy.newInstance(connector, clientTimeOut); KeyValuePairCompat<T, HttpClient> returnValue = new KeyValuePairCompat<T, HttpClient>(asyncConnector, httpclient); return returnValue; } private static class AsyncProxy implements InvocationHandler { private Object obj; private long timeoutInMilisec; public static Object newInstance(Object obj, long timeoutInMilisec) { return Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), obj.getClass().getInterfaces(), new AsyncProxy(obj, timeoutInMilisec)); } private AsyncProxy(Object obj, long timeoutInMilisec) { this.obj = obj; this.timeoutInMilisec = timeoutInMilisec; } @Override public Object invoke(Object proxy, final Method m, final Object[] args) throws Throwable { Object result; FutureTask<Object> future = new FutureTask<Object>(new Callable<Object>() { public Object call() throws Exception { try { return m.invoke(obj, args); } catch (Exception e) { throw e; } } }); ThreadPoolUtil.execute(future); try { result = future.get(timeoutInMilisec, TimeUnit.MILLISECONDS); } catch (Exception e) { if (e instanceof TimeoutException) { future.cancel(true); } throw new UndeclaredThrowableException(e); } return result; } } }