001    /*
002     * The Apache Software License, Version 1.1
003     *
004     * Copyright (c) 2001-2004 Caucho Technology, Inc.  All rights reserved.
005     *
006     * Redistribution and use in source and binary forms, with or without
007     * modification, are permitted provided that the following conditions
008     * are met:
009     *
010     * 1. Redistributions of source code must retain the above copyright
011     *    notice, this list of conditions and the following disclaimer.
012     *
013     * 2. Redistributions in binary form must reproduce the above copyright
014     *    notice, this list of conditions and the following disclaimer in
015     *    the documentation and/or other materials provided with the
016     *    distribution.
017     *
018     * 3. The end-user documentation included with the redistribution, if
019     *    any, must include the following acknowlegement:
020     *       "This product includes software developed by the
021     *        Caucho Technology (http://www.caucho.com/)."
022     *    Alternately, this acknowlegement may appear in the software itself,
023     *    if and wherever such third-party acknowlegements normally appear.
024     *
025     * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
026     *    endorse or promote products derived from this software without prior
027     *    written permission. For written permission, please contact
028     *    info@caucho.com.
029     *
030     * 5. Products derived from this software may not be called "Resin"
031     *    nor may "Resin" appear in their names without prior written
032     *    permission of Caucho Technology.
033     *
034     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037     * DISCLAIMED.  IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038     * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039     * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040     * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041     * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044     * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045     *
046     * @author Scott Ferguson
047     */
048    
049    package com.caucho.burlap.client;
050    
051    import com.caucho.burlap.io.AbstractBurlapInput;
052    import com.caucho.burlap.io.BurlapOutput;
053    
054    import java.io.FileNotFoundException;
055    import java.io.IOException;
056    import java.io.InputStream;
057    import java.io.OutputStream;
058    import java.lang.reflect.InvocationHandler;
059    import java.lang.reflect.Method;
060    import java.lang.reflect.Proxy;
061    import java.net.HttpURLConnection;
062    import java.net.URL;
063    import java.net.URLConnection;
064    import java.util.logging.*;
065    
066    /**
067     * Proxy implementation for Burlap clients.  Applications will generally
068     * use BurlapProxyFactory to create proxy clients.
069     */
070    public class BurlapProxy implements InvocationHandler {
071      private static final Logger log
072        = Logger.getLogger(BurlapProxy.class.getName());
073      
074      private BurlapProxyFactory _factory;
075      private URL _url;
076      
077      BurlapProxy(BurlapProxyFactory factory, URL url)
078      {
079        _factory = factory;
080        _url = url;
081      }
082    
083      /**
084       * Returns the proxy's URL.
085       */
086      public URL getURL()
087      {
088        return _url;
089      }
090    
091      /**
092       * Handles the object invocation.
093       *
094       * @param proxy the proxy object to invoke
095       * @param method the method to call
096       * @param args the arguments to the proxy object
097       */
098      public Object invoke(Object proxy, Method method, Object []args)
099        throws Throwable
100      {
101        String methodName = method.getName();
102        Class []params = method.getParameterTypes();
103    
104        // equals and hashCode are special cased
105        if (methodName.equals("equals") &&
106            params.length == 1 && params[0].equals(Object.class)) {
107          Object value = args[0];
108          if (value == null || ! Proxy.isProxyClass(value.getClass()))
109            return new Boolean(false);
110    
111          BurlapProxy handler = (BurlapProxy) Proxy.getInvocationHandler(value);
112    
113          return new Boolean(_url.equals(handler.getURL()));
114        }
115        else if (methodName.equals("hashCode") && params.length == 0)
116          return new Integer(_url.hashCode());
117        else if (methodName.equals("getBurlapType"))
118          return proxy.getClass().getInterfaces()[0].getName();
119        else if (methodName.equals("getBurlapURL"))
120          return _url.toString();
121        else if (methodName.equals("toString") && params.length == 0)
122          return getClass().getSimpleName() +  "[" + _url + "]";
123    
124        InputStream is = null;
125        
126        URLConnection conn = null;
127        HttpURLConnection httpConn = null;
128        try {
129          conn = _factory.openConnection(_url);
130          
131          httpConn = (HttpURLConnection) conn;
132          
133          httpConn.setRequestMethod("POST");
134          conn.setRequestProperty("Content-Type", "text/xml");
135    
136          OutputStream os;
137    
138          try {
139            os = conn.getOutputStream();
140          } catch (Exception e) {
141            throw new BurlapRuntimeException(e);
142          }
143    
144          BurlapOutput out = _factory.getBurlapOutput(os);
145    
146          if (! _factory.isOverloadEnabled()) {
147          }
148          else if (args != null)
149            methodName = methodName + "__" + args.length;
150          else
151            methodName = methodName + "__0";
152    
153          if (log.isLoggable(Level.FINE))
154            log.fine(this + " calling " + methodName + " (" + method + ")");
155    
156          out.call(methodName, args);
157    
158          try {
159            os.flush();
160          } catch (Exception e) {
161            throw new BurlapRuntimeException(e);
162          }
163    
164          if (conn instanceof HttpURLConnection) {
165            httpConn = (HttpURLConnection) conn;
166            int code = 500;
167    
168            try {
169              code = httpConn.getResponseCode();
170            } catch (Exception e) {
171            }
172    
173            if (code != 200) {
174              StringBuffer sb = new StringBuffer();
175              int ch;
176    
177              try {
178                is = httpConn.getInputStream();
179    
180                if (is != null) {
181                  while ((ch = is.read()) >= 0)
182                    sb.append((char) ch);
183    
184                  is.close();
185                }
186    
187                is = httpConn.getErrorStream();
188                if (is != null) {
189                  while ((ch = is.read()) >= 0)
190                    sb.append((char) ch);
191                }
192              } catch (FileNotFoundException e) {
193                throw new BurlapRuntimeException(code + ": " + String.valueOf(e));
194              } catch (IOException e) {
195              }
196    
197              if (is != null)
198                is.close();
199    
200              throw new BurlapProtocolException(code + ": " + sb.toString());
201            }
202          }
203    
204          is = conn.getInputStream();
205    
206          AbstractBurlapInput in = _factory.getBurlapInput(is);
207    
208          return in.readReply(method.getReturnType());
209        } catch (BurlapProtocolException e) {
210          throw new BurlapRuntimeException(e);
211        } finally {
212          try {
213            if (is != null)
214              is.close();
215          } catch (IOException e) {
216          }
217          
218          if (httpConn != null)
219            httpConn.disconnect();
220        }
221      }
222    
223      public String toString()
224      {
225        return getClass().getSimpleName() + "[" + _url + "]";
226      }
227    }