EMMA Coverage Report (generated Tue Feb 12 22:23:49 ICT 2008)
[all classes][net.sourceforge.hiveremoting.caucho]

COVERAGE SUMMARY FOR SOURCE FILE [AbstractCauchoProxy.java]

nameclass, %method, %block, %line, %
AbstractCauchoProxy.java0%   (0/1)0%   (0/9)0%   (0/538)0%   (0/108)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AbstractCauchoProxy0%   (0/1)0%   (0/9)0%   (0/538)0%   (0/108)
AbstractCauchoProxy (CauchoProxyContribution, SerializerFactory, HttpConnecti... 0%   (0/1)0%   (0/61)0%   (0/15)
close (InputStream): void 0%   (0/1)0%   (0/12)0%   (0/6)
getActualMethodName (String, Object []): String 0%   (0/1)0%   (0/31)0%   (0/7)
getResponseStream (PostMethod): InputStream 0%   (0/1)0%   (0/28)0%   (0/7)
initRemoteContext (PostMethod): void 0%   (0/1)0%   (0/32)0%   (0/7)
invoke (Object, Method, Object []): Object 0%   (0/1)0%   (0/189)0%   (0/33)
invokeSpecialMethod (Object, String, Class [], Object []): Object 0%   (0/1)0%   (0/99)0%   (0/15)
prepareRequest (ByteArrayOutputStream, PostMethod): void 0%   (0/1)0%   (0/46)0%   (0/11)
retrieveRemoteContext (int, PostMethod): void 0%   (0/1)0%   (0/40)0%   (0/7)

1//  Copyright 2004-2007 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14 
15package net.sourceforge.hiveremoting.caucho;
16 
17import java.io.BufferedInputStream;
18import java.io.ByteArrayOutputStream;
19import java.io.IOException;
20import java.io.InputStream;
21import java.io.OutputStream;
22import java.lang.reflect.InvocationHandler;
23import java.lang.reflect.Method;
24import java.lang.reflect.Proxy;
25import java.util.HashMap;
26import java.util.Map;
27import java.util.zip.GZIPInputStream;
28import java.util.zip.GZIPOutputStream;
29 
30import org.apache.commons.httpclient.Credentials;
31import org.apache.commons.httpclient.Header;
32import org.apache.commons.httpclient.HttpClient;
33import org.apache.commons.httpclient.HttpConnectionManager;
34import org.apache.commons.httpclient.HttpStatus;
35import org.apache.commons.httpclient.UsernamePasswordCredentials;
36import org.apache.commons.httpclient.auth.AuthScope;
37import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
38import org.apache.commons.httpclient.methods.PostMethod;
39import org.apache.commons.logging.Log;
40 
41import com.caucho.hessian.io.SerializerFactory;
42 
43/**
44 * Abstract dynamic proxy for Caucho protocols on client side (used for Hessian
45 * and Burlap).
46 * <p>
47 * This proxy is based on commons-httpclient for better connection management.
48 * In particular, it handles cookies, https.
49 *
50 * @author        Jean-Francois Poilpret
51 */
52public abstract class AbstractCauchoProxy implements InvocationHandler
53{
54        protected AbstractCauchoProxy(        CauchoProxyContribution        contrib,
55                                                                        SerializerFactory                factory,
56                                                                        HttpConnectionManager        cnxManager,
57                                                                        Log                                                logger)
58        {
59                _logger = logger;
60                _factory = factory;
61                _overloadEnabled = contrib.getOverloadEnabled();
62                _url = contrib.getUrl();
63                _gzipThreshold = contrib.getGzipThreshold();
64                _gzipInBufferSize = contrib.getGzipInBufferSize();
65                _handler = contrib.getContextHandler();
66                _callContextHandlerOnError = contrib.getCallContextHandlerOnError();
67                _httpClient = new HttpClient(cnxManager);
68                _httpClient.getParams().setAuthenticationPreemptive(true);
69                if (contrib.getUser() != null)
70                {
71                        Credentials credentials = new UsernamePasswordCredentials(
72                                                                                contrib.getUser(), contrib.getPassword());
73                        _httpClient.getState().setCredentials(AuthScope.ANY, credentials);
74                }
75        }
76 
77        // CSOFF: CyclomaticComplexityCheck
78        private Object        invokeSpecialMethod(Object                proxy,
79                                                                                String                method,
80                                                                                Class[]                params,
81                                                                                Object[]        args)
82        {
83                // Special cases first (same behavior as default Caucho proxies)
84                if (        method.equals("equals")
85                        &&        params.length == 1
86                        &&        params[0].equals(Object.class))
87                {
88                        Object value = args[0];
89                        if (value == null || !Proxy.isProxyClass(value.getClass()))
90                        {
91                                return Boolean.FALSE;
92                        }
93                
94                        AbstractCauchoProxy handler = 
95                                                (AbstractCauchoProxy) Proxy.getInvocationHandler(value);
96                        return Boolean.valueOf(_url.equals(handler._url));
97                }
98                else if (method.equals("hashCode") && params.length == 0)
99                {
100                        return new Integer(_url.hashCode());
101                }
102                else if (        method.equals("getHessianType")
103                                ||        method.equals("getBurlapType"))
104                {
105                        return proxy.getClass().getInterfaces()[0].getName();
106                }
107                else if (        method.equals("getHessianURL")
108                                ||        method.equals("getBurlapURL"))
109                {
110                        return _url.toString();
111                }
112                else if (method.equals("toString") && params.length == 0)
113                {
114                        return "[CauchoProxy " + _url + "]";
115                }
116                else
117                {
118                        // This is not a special method, return null as an indicator
119                        return null;
120                }
121        }
122        // CSON: CyclomaticComplexityCheck
123 
124        private void        initRemoteContext(PostMethod post)
125        {
126                if (_handler != null)
127                {
128                        Map<String, String> context = new HashMap<String, String>();
129                        _handler.initContext(context);
130                        for (Map.Entry<String, String> entry: context.entrySet())
131                        {
132                                post.setRequestHeader(entry.getKey(), entry.getValue());
133                        }
134                }
135        }
136        
137        private void        retrieveRemoteContext(int code, PostMethod post)
138        {
139                if (        _handler != null
140                        &&        (_callContextHandlerOnError || code ==  HttpStatus.SC_OK))
141                {
142                        Map<String, String> context = new HashMap<String, String>();
143                        Header[] headers = post.getResponseHeaders();
144                        for (int i = 0; i < headers.length; i++)
145                        {
146                                context.put(headers[i].getName(), headers[i].getValue());
147                        }
148                        _handler.extractContext(context);
149                }
150        }
151        
152        private String        getActualMethodName(String method, Object[] args)
153        {
154                String methodName = method;
155                if (_overloadEnabled)
156                {
157                        if (args != null)
158                        {
159                                methodName = methodName + "__" + args.length;
160                        }
161                        else
162                        {
163                                methodName = methodName + "__0";
164                        }
165                }
166                return methodName;
167        }
168        
169        private void        prepareRequest(ByteArrayOutputStream stream, PostMethod post)
170                throws IOException
171        {
172                if (_gzipThreshold >= 0 && stream.size() > _gzipThreshold)
173                {
174                        ByteArrayOutputStream output = new ByteArrayOutputStream();                                
175                        GZIPOutputStream gzipOutput = new GZIPOutputStream(output);
176                        stream.writeTo(gzipOutput);
177                        gzipOutput.finish();
178                        gzipOutput.close();
179                        post.setRequestHeader("Content-Encoding", "gzip");
180                        post.setRequestEntity(new ByteArrayRequestEntity(output.toByteArray(), "text/xml"));
181                }
182                else
183                {
184                        post.setRequestEntity(new ByteArrayRequestEntity(stream.toByteArray(), "text/xml"));
185                }
186        }
187        
188        private InputStream        getResponseStream(PostMethod post)
189                throws IOException
190        {
191                InputStream        is = post.getResponseBodyAsStream();
192                Header encodingHeader = post.getResponseHeader("Content-Encoding");
193                if (encodingHeader != null)
194                {
195                        String encoding = encodingHeader.getValue();
196                        // GZIP management for response
197                        if ("gzip".equals(encoding))
198                        {
199                                is = new BufferedInputStream(new GZIPInputStream(is), _gzipInBufferSize);
200                        }
201                }
202                return is;
203        }
204        
205        //CSOFF: IllegalThrowsCheck
206        public Object        invoke(Object proxy, Method method, Object[] args)
207                throws Throwable
208        {
209                String methodName = method.getName();
210                Class[] params = method.getParameterTypes();
211 
212                // Special cases first (same behavior as default Caucho proxies)
213                Object special = invokeSpecialMethod(proxy, methodName, params, args);
214                if (special != null)
215                {
216                        return special;
217                }
218 
219                // Actual remoting takes place here
220                InputStream is = null;
221                PostMethod post = new PostMethod(_url);
222                initRemoteContext(post);
223 
224                long time = 0;
225                try
226                {
227                        // Calculate actual method name
228                        methodName = getActualMethodName(methodName, args);
229 
230                        // GZIP management for request
231                        if (_gzipThreshold >= 0)
232                        {
233                                post.setRequestHeader("Accept-Encoding", "gzip, identity");
234                        }
235                        // Serialize whole method call through HessianOutput/BurlapOutput
236                        // into memory buffer
237                        ByteArrayOutputStream os = new ByteArrayOutputStream();
238                        callMethod(os, methodName, args);
239                        // Gzip message if required
240                        prepareRequest(os, post);
241                        os = null;
242 
243                        // Execute method
244                        int code = _httpClient.executeMethod(post);
245                        // Get Body and unserialize it through HessianInput
246                        is = getResponseStream(post);
247                        // Get context
248                        retrieveRemoteContext(code, post);
249                        if (code == HttpStatus.SC_OK)
250                        {
251                                time = System.currentTimeMillis();
252                                return getReturnValue(is, method.getReturnType());
253                        }
254                        else
255                        {
256                                _logger.info(        "invoke " + method.getName() + "(), status line: " +
257                                                                post.getStatusLine());
258                                throw createException(post.getStatusLine().toString());
259                        }
260                }
261                catch (IOException e)
262                {
263                        _logger.error("invoke " + method.getName(), e);
264                        throw createException(e);
265                }
266                finally
267                {
268                        if (_logger.isDebugEnabled())
269                        {
270                                time = System.currentTimeMillis() - time;
271                                _logger.debug(        "invoke " + method.getName() + 
272                                                                "(), unzip time = " + time + " ms");
273                        }
274                        close(is);
275                        post.releaseConnection();
276                }
277        }
278        //CSON: IllegalThrowsCheck
279        
280        protected void        close(InputStream is)
281        {
282                //#### Should we also try to read it to its end?
283                try
284                {
285                        if (is != null)
286                        {
287                                is.close();
288                        }
289                }
290                catch (IOException e)
291                {
292                        // What more can we do here?
293                        _logger.error("close", e);
294                }
295        }
296        
297        //CSOFF: IllegalThrowsCheck
298        abstract protected void                callMethod(OutputStream os, String method, Object[] args)
299                throws Throwable;
300        abstract protected Object        getReturnValue(InputStream is, Class type)
301                throws Throwable;
302        //CSON: IllegalThrowsCheck
303 
304        abstract protected RuntimeException        createException(String message);
305        abstract protected RuntimeException        createException(Throwable cause);
306        
307        protected final        Log                                                _logger;
308        protected final HttpClient                                _httpClient;
309        protected final String                                        _url;
310        protected final boolean                                        _overloadEnabled;
311        protected final SerializerFactory                _factory;
312        protected final int                                                _gzipThreshold;
313        protected final int                                                _gzipInBufferSize;
314    protected final RemoteContextHandler        _handler;
315    protected final boolean                                        _callContextHandlerOnError;
316}

[all classes][net.sourceforge.hiveremoting.caucho]
EMMA 2.0.5312 (C) Vladimir Roubtsov