View Javadoc

1   /* (c) Copyright 2003 Caleigo AB, All rights reserved. 
2    * 
3    * This library is free software; you can redistribute it and/or
4    * modify it under the terms of the GNU Lesser General Public
5    * License as published by the Free Software Foundation; either
6    * version 2.1 of the License, or (at your option) any later version.
7    * 
8    * This library is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   * Lesser General Public License for more details.
12   * 
13   * You should have received a copy of the GNU Lesser General Public
14   * License along with this library; if not, write to the Free Software
15   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   *  
17   */
18  
19  package org.caleigo.toolkit.tunnel;
20  
21  
22  import java.io.*;
23  import java.net.*;
24  
25  import org.caleigo.toolkit.log.*;
26  
27  /***
28   *
29   * @author  Mattias Hagstrand
30   * @version 1.00
31   * 
32   *//*
33   *
34   * WHEN        WHO               WHY & WHAT
35   * -----------------------------------------------------------------------------
36   * 2002-07-02  Mattias Hagstrand Creation
37   */
38  public class HTTPTunnel extends AbstractTunnel
39  {
40      // Data members ------------------------------------------------------------
41      protected URL mURL;
42      protected OutputStream mOutputStream;
43      protected InputStream mInputStream;
44      protected int mSessionID = -1;
45      
46      private boolean mIsInitialized;
47      
48      // Constructors ------------------------------------------------------------
49      protected HTTPTunnel(InputStream inputStream, OutputStream outputStream)
50      {
51          super();
52          mOutputStream = outputStream;
53          mInputStream = inputStream;
54      }
55      
56      public HTTPTunnel(URL url)
57      {
58          if (url.getProtocol().compareToIgnoreCase("http") != 0)
59              throw new IllegalArgumentException("Unknown protocol: " + url.getProtocol());
60          
61          mURL = url;
62      }
63      
64      public HTTPTunnel(URL url, ITunnelCodec codec)
65      {
66          super(codec);
67          
68          if (url.getProtocol().compareToIgnoreCase("http") != 0)
69              throw new IllegalArgumentException("Unknown protocol: " + url.getProtocol());
70          
71          mURL = url;
72      }
73      
74      // Superclass overrides ----------------------------------------------------
75      public synchronized void initialize()
76          throws IllegalStateException, TunnelException
77      {
78          if (mIsInitialized)
79              throw new IllegalStateException("The tunnel is initialized");
80  
81          try
82          {
83              if (mInputStream == null || mOutputStream == null)
84                  this.setUpConnection();
85              
86              super.initialize();
87              
88              mIsInitialized = true;
89          }
90          catch (Exception e)
91          {
92              throw new TunnelException(e);
93          }
94      }
95      
96      public synchronized void finalize()
97          throws IllegalStateException, TunnelException
98      {
99          if (!mIsInitialized)
100             throw new IllegalStateException("The tunnel is not initialized");
101         
102         if (super.isActive())
103             this.send(new HTTPTunnelCloseMessage(mSessionID));
104         try
105         {
106             if (super.isActive())
107                 super.finalize();
108             //mHttpURLConnection.disconnect();
109         }
110         catch (Exception e)
111         {
112             throw new TunnelException(e);
113         }
114         finally
115         {
116             //mHttpURLConnection = null;
117             mOutputStream = null;
118             mInputStream = null;
119             mIsInitialized = false;
120             mSessionID = -1;
121         }
122     }
123     
124     /*** Returns <code>true</code> if this tunnel is active, that is, if it is
125      * correctly initialized. If this method returns <code>true</code> then
126      * a call to finalize must not throw an IllegalStateException.
127      */
128     public synchronized boolean isActive()
129     {
130         return mIsInitialized;
131     }
132     
133     /***
134      * Returns an OutputStream that should be used to send messages.
135      */
136     protected OutputStream getOutputStream()
137     {
138         return mOutputStream;
139     }
140     
141     /***
142      * Returns an InputStream that should be used to receive messages.
143      */
144     protected InputStream getInputStream()
145     {
146         return mInputStream;
147     }
148         
149     // Help methods ------------------------------------------------------------
150     protected HttpURLConnection createConnection()
151         throws IOException
152     {
153         HttpURLConnection httpURLConnection = (HttpURLConnection) mURL.openConnection();
154         httpURLConnection.setAllowUserInteraction(true);
155         httpURLConnection.setDoOutput(true);
156         httpURLConnection.setDoInput(true);
157         httpURLConnection.setUseCaches(false);
158         httpURLConnection.setRequestMethod("POST");
159         httpURLConnection.setRequestProperty("content-type", "application/octet-stream");
160         
161         return httpURLConnection;
162     }
163     
164     protected void setUpConnection()
165         throws TunnelException
166     {
167         HTTPTunnelStatusMessage statusMessage = null;
168         
169         try
170         {
171             HttpURLConnection httpURLConnection = this.createConnection();
172             ObjectOutputStream objectOutputStream = new ObjectOutputStream(httpURLConnection.getOutputStream());
173             
174             // Send connection message
175             objectOutputStream.writeObject(this.createConnectionMessage());
176             objectOutputStream.flush();
177             objectOutputStream.close();
178             
179             // Wait for reply from server
180             mInputStream = httpURLConnection.getInputStream();
181             ObjectInputStream objectInputStream = new ObjectInputStream(mInputStream);
182             statusMessage = (HTTPTunnelStatusMessage) objectInputStream.readObject();
183         }
184         catch (Exception e)
185         {
186             throw new TunnelException(e);
187         }
188         
189         if (statusMessage.getStatus() == IStatusMessage.OK)
190         {
191             if (this.getLogLevel() <= AbstractTunnel.INFO)
192                 Log.print(this, "Status message received: " + statusMessage.toString());
193             for (int i = 0; i < mStatusCallbacks.size(); i++)
194                 ((IStatusCallback) mStatusCallbacks.get(i)).handleInfo("Connection established");
195             
196             mSessionID = statusMessage.getSessionID();
197             mOutputStream = new HTTPTunnelOutputStream(mSessionID);
198         }
199         else
200         {
201             if (this.getLogLevel() <= ERROR)
202                 Log.printError(this, "Couldn't establish connection: " + statusMessage.getMessage());
203             for (int i = 0; i < mStatusCallbacks.size(); i++)
204                 ((IStatusCallback) mStatusCallbacks.get(i)).handleError("Couldn't establish connection: " + statusMessage.getMessage(), null);
205             throw new TunnelException("Couldn't establish connection: " + statusMessage.getMessage());
206         }
207     }
208     
209     // Nested classes ----------------------------------------------------------
210     protected static class HTTPTunnelStatusMessage extends DefaultStatusMessage
211     {
212         // Data members --------------------------------------------------------
213         protected int mSessionID;
214         
215         // Constructors --------------------------------------------------------
216         public HTTPTunnelStatusMessage(IStatusMessage statusMessage, int sessionID)
217         {
218             this(statusMessage.getStatus(), statusMessage.getMessage(), sessionID);
219         }
220         
221         public HTTPTunnelStatusMessage(int status, String message, int sessionID)
222         {
223             super(status, message);
224             mSessionID = sessionID;
225         }
226         // Access methods ------------------------------------------------------
227         public int getSessionID()
228         {
229             return mSessionID;
230         }
231     }
232     
233     protected static class HTTPTunnelCloseMessage implements IFinalizeMessage
234     {
235         // Data members --------------------------------------------------------
236         protected int mSessionID;
237         
238         // Constructors --------------------------------------------------------
239         public HTTPTunnelCloseMessage(int sessionID)
240         {
241             mSessionID = sessionID;
242         }
243         
244         // Access methods ------------------------------------------------------
245         public int getSessionID()
246         {
247             return mSessionID;
248         }
249     }
250     
251     protected static class HTTPTunnelPackage implements Serializable
252     {
253         // Data members --------------------------------------------------------
254         protected int mSessionID;
255         protected Object mMessage;
256         
257         // Constructors --------------------------------------------------------
258         public HTTPTunnelPackage(int sessionID, Object message)
259         {
260             mSessionID = sessionID;
261             mMessage = message;
262         }
263         // Access methods ------------------------------------------------------
264         public int getSessionID()
265         {
266             return mSessionID;
267         }
268         
269         public Object getMessage()
270         {
271             return mMessage;
272         }
273     }
274     
275     protected class HTTPTunnelOutputStream extends OutputStream
276     {
277         // Data members --------------------------------------------------------
278         protected int mSessionID;
279         protected ByteArrayOutputStream mBuffer;
280         
281         // Constructors --------------------------------------------------------
282         public HTTPTunnelOutputStream(int sessionID)
283         {
284             mSessionID = sessionID;
285             mBuffer = new ByteArrayOutputStream(1024);
286         }
287         
288         // Superclass overrides ------------------------------------------------
289         public void close()
290             throws IOException
291         {
292             mBuffer.close();
293             //this.sendMessage(new HTTPTunnelCloseMessage());
294         }
295         
296         public void write(byte[] b)
297             throws IOException
298         {
299             mBuffer.write(b);
300         }
301         
302         public void write(byte[] b, int off, int len)
303             throws IOException
304         {
305             mBuffer.write(b, off, len);
306         }
307         
308         public void write(int b)
309             throws IOException
310         {
311             // Write the byte in the buffer
312             mBuffer.write(b);
313         }
314         
315         public void flush()
316             throws IOException
317         {
318             byte[] bufferData = mBuffer.toByteArray();
319             //Log.print(this, "flush(): " + bufferData.length);
320             this.sendMessage(bufferData);
321             mBuffer.reset();
322         }
323         
324         // Help methods --------------------------------------------------------
325         protected void sendMessage(Object message)
326             throws IOException
327         {
328             HttpURLConnection httpURLConnection = createConnection();
329             ObjectOutputStream objectOutputStream = new ObjectOutputStream(httpURLConnection.getOutputStream());
330             HTTPTunnelPackage tunnelPackage = new HTTPTunnelPackage(mSessionID, message);
331             objectOutputStream.writeObject(tunnelPackage);
332             objectOutputStream.flush();
333             objectOutputStream.close();
334             httpURLConnection.getInputStream().close();
335         }
336     }
337 }