Coverage Report - org.simject.remoting.client.HttpClientProxy
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpClientProxy
21%
12/58
6%
1/16
0
 
 1  
 /*
 2  
  * Copyright 2008 Simon Martinelli, Rebenweg 32, 3236 Gampelen, Switzerland
 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  
 package org.simject.remoting.client;
 17  
 
 18  
 import java.beans.XMLDecoder;
 19  
 import java.beans.XMLEncoder;
 20  
 import java.io.ObjectInputStream;
 21  
 import java.io.ObjectOutputStream;
 22  
 import java.lang.reflect.InvocationHandler;
 23  
 import java.lang.reflect.Method;
 24  
 import java.net.HttpURLConnection;
 25  
 import java.net.MalformedURLException;
 26  
 import java.net.URL;
 27  
 import java.util.logging.Level;
 28  
 import java.util.logging.Logger;
 29  
 
 30  
 import org.simject.util.Protocol;
 31  
 import org.simject.util.SimConstants;
 32  
 
 33  
 /**
 34  
  * Used to provide remote access over HTTP to a resource. HttpClientProxy uses
 35  
  * XStream for XML serialization or normal Java serialization for binary
 36  
  * protocol
 37  
  * 
 38  
  * @author Simon Martinelli
 39  
  */
 40  
 public final class HttpClientProxy implements InvocationHandler {
 41  
 
 42  1
         private final static Logger logger = Logger.getLogger(HttpClientProxy.class
 43  
                         .getName());
 44  
 
 45  
         /**
 46  
          * Holds the requested URL
 47  
          */
 48  
         final private URL url;
 49  
 
 50  
         /**
 51  
          * Holds the protocol
 52  
          */
 53  
         final private Protocol protocol;
 54  
 
 55  
         /**
 56  
          * Creates a new instance of a proxy
 57  
          * 
 58  
          * @param loader
 59  
          * @param interfaces
 60  
          * @param url
 61  
          * @return an instance of HttpClientProxy
 62  
          * @throws MalformedURLException
 63  
          */
 64  
         public static Object newInstance(final ClassLoader loader,
 65  
                         final Class<?>[] interfaces, final String target)
 66  
                         throws MalformedURLException {
 67  
 
 68  
                 // Extract the protocol
 69  6
                 final String protcolString = target.substring(0, 3);
 70  6
                 Protocol protocol = Protocol.Xml;
 71  6
                 if (protcolString.equals(Protocol.Binary.getString())) {
 72  0
                         protocol = Protocol.Binary;
 73  
                 }
 74  
                 // Extract the URL
 75  6
                 final String urlString = target.substring(4);
 76  6
                 final URL url = new URL(urlString);
 77  
 
 78  6
                 logger.info("Creating proxy for URL <" + url + "> using <" + protocol
 79  
                                 + "> protocol");
 80  
                 // Create an instance of the proxy
 81  6
                 return java.lang.reflect.Proxy.newProxyInstance(loader, interfaces,
 82  
                                 new HttpClientProxy(url, protocol));
 83  
         }
 84  
 
 85  
         /**
 86  
          * Private Constructor
 87  
          * 
 88  
          * @param url
 89  
          */
 90  6
         private HttpClientProxy(final URL url, final Protocol protocol) {
 91  6
                 this.url = url;
 92  6
                 this.protocol = protocol;
 93  6
         }
 94  
 
 95  
         @Override
 96  
         public Object invoke(final Object proxy, final Method method,
 97  
                         final Object[] args) throws Throwable {
 98  0
                 logger.info("Invoking method <" + method.getName()
 99  
                                 + "> with arguments <" + args + ">");
 100  
                 Object result;
 101  
                 try {
 102  0
                         if (protocol == Protocol.Binary) {
 103  0
                                 result = this.invokeUrlBinary2(method, args);
 104  
                         } else {
 105  0
                                 result = this.invokeUrlXml2(method, args);
 106  
                         }
 107  0
                 } catch (Exception e) {
 108  0
                         logger.log(Level.SEVERE, e.getMessage(), e);
 109  0
                         throw e;
 110  0
                 }
 111  0
                 return result;
 112  
         }
 113  
 
 114  
         /**
 115  
          * Synchronous call over HTTP using binary protocol
 116  
          * 
 117  
          * 1. Serializes the arguments to Binary and make a remote call over HTTP
 118  
          * with Commons HttpClient to the desired method. 2. Deserializes the binary
 119  
          * response from the server.
 120  
          * 
 121  
          * @param method
 122  
          * @param args
 123  
          * @return
 124  
          * @throws Throwable
 125  
          */
 126  
         private Object invokeUrlBinary2(final Method method, final Object[] args)
 127  
                         throws Throwable {
 128  
 
 129  0
                 HttpURLConnection con = (HttpURLConnection) this.url.openConnection();
 130  0
                 con.setDoOutput(true);
 131  
 
 132  
                 // The method name and the parameter types are set to the header
 133  0
                 this.createHeader2(method, con);
 134  
 
 135  0
                 final ObjectOutputStream oos = new ObjectOutputStream(con
 136  
                                 .getOutputStream());
 137  0
                 oos.writeObject(args);
 138  0
                 oos.close();
 139  
 
 140  
                 // Get response if the content is > 0
 141  0
                 Object result = null;
 142  0
                 if (con.getContentLength() > 0) {
 143  0
                         final ObjectInputStream ois = new ObjectInputStream(con
 144  
                                         .getInputStream());
 145  0
                         result = ois.readObject();
 146  
 
 147  0
                         if (result instanceof Throwable) {
 148  0
                                 throw ((Throwable) result);
 149  
                         }
 150  
                 }
 151  
 
 152  0
                 con.disconnect();
 153  
 
 154  0
                 return result;
 155  
         }
 156  
 
 157  
         /**
 158  
          * Synchronous call over HTTP using XML protocol
 159  
          * 
 160  
          * 1. Serializes the arguments to XML using XMLEncoder and make a remote
 161  
          * call over HTTP with Commons HttpClient to the desired method. 2.
 162  
          * Deserializes the XML response from the server using XMLDecoder.
 163  
          * 
 164  
          * @param method
 165  
          * @param args
 166  
          * @return
 167  
          * @throws Throwable
 168  
          */
 169  
         private Object invokeUrlXml2(final Method method, final Object[] args)
 170  
                         throws Throwable {
 171  
 
 172  0
                 final HttpURLConnection con = (HttpURLConnection) this.url
 173  
                                 .openConnection();
 174  0
                 con.setDoOutput(true);
 175  
 
 176  
                 // The method name and the parameter types are set to the header
 177  0
                 this.createHeader2(method, con);
 178  
 
 179  0
                 final XMLEncoder encoder = new XMLEncoder(con.getOutputStream());
 180  0
                 encoder.writeObject(args);
 181  
 
 182  
                 // Get response if the content is > 0
 183  0
                 Object result = null;
 184  0
                 if (con.getContentLength() > 0) {
 185  0
                         final XMLDecoder decoder = new XMLDecoder(con.getInputStream());
 186  0
                         result = decoder.readObject();
 187  0
                         if (result instanceof Throwable) {
 188  0
                                 throw ((Throwable) result);
 189  
                         }
 190  
                 }
 191  
 
 192  0
                 con.disconnect();
 193  
 
 194  0
                 return result;
 195  
         }
 196  
 
 197  
         /**
 198  
          * Create the necessairy Header entries
 199  
          * 
 200  
          * @param method
 201  
          * @param post
 202  
          */
 203  
         private void createHeader2(final Method method, final HttpURLConnection con) {
 204  0
                 con.setRequestProperty(SimConstants.PARAM_METHOD, method.getName());
 205  
 
 206  
                 // Get all parameter types and add them to a string delimited by ,
 207  0
                 final StringBuffer params = new StringBuffer();
 208  0
                 for (Class<?> param : method.getParameterTypes()) {
 209  0
                         final String paramString = param.getName()
 210  
                                         + SimConstants.PARAM_TYPE_DELIM;
 211  0
                         params.append(paramString);
 212  
                 }
 213  0
                 if (params.length() > 0) {
 214  0
                         final String parameters = params.toString();
 215  0
                         con.setRequestProperty(SimConstants.PARAM_TYPES, parameters);
 216  
                 }
 217  0
         }
 218  
 }