1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
41 protected URL mURL;
42 protected OutputStream mOutputStream;
43 protected InputStream mInputStream;
44 protected int mSessionID = -1;
45
46 private boolean mIsInitialized;
47
48
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
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
109 }
110 catch (Exception e)
111 {
112 throw new TunnelException(e);
113 }
114 finally
115 {
116
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
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
175 objectOutputStream.writeObject(this.createConnectionMessage());
176 objectOutputStream.flush();
177 objectOutputStream.close();
178
179
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
210 protected static class HTTPTunnelStatusMessage extends DefaultStatusMessage
211 {
212
213 protected int mSessionID;
214
215
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
227 public int getSessionID()
228 {
229 return mSessionID;
230 }
231 }
232
233 protected static class HTTPTunnelCloseMessage implements IFinalizeMessage
234 {
235
236 protected int mSessionID;
237
238
239 public HTTPTunnelCloseMessage(int sessionID)
240 {
241 mSessionID = sessionID;
242 }
243
244
245 public int getSessionID()
246 {
247 return mSessionID;
248 }
249 }
250
251 protected static class HTTPTunnelPackage implements Serializable
252 {
253
254 protected int mSessionID;
255 protected Object mMessage;
256
257
258 public HTTPTunnelPackage(int sessionID, Object message)
259 {
260 mSessionID = sessionID;
261 mMessage = message;
262 }
263
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
278 protected int mSessionID;
279 protected ByteArrayOutputStream mBuffer;
280
281
282 public HTTPTunnelOutputStream(int sessionID)
283 {
284 mSessionID = sessionID;
285 mBuffer = new ByteArrayOutputStream(1024);
286 }
287
288
289 public void close()
290 throws IOException
291 {
292 mBuffer.close();
293
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
312 mBuffer.write(b);
313 }
314
315 public void flush()
316 throws IOException
317 {
318 byte[] bufferData = mBuffer.toByteArray();
319
320 this.sendMessage(bufferData);
321 mBuffer.reset();
322 }
323
324
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 }