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 import java.util.*;
22
23 import org.caleigo.toolkit.log.Log;
24
25
26 /***
27 *
28 * @author Mattias Hagstrand
29 * @version 1.00
30 *
31 *//*
32 *
33 * WHEN WHO WHY & WHAT
34 * -----------------------------------------------------------------------------
35 * 2002-07-02 Mattias Hagstrand Creation
36 */
37 public class AbstractTunnelServer implements ITunnelServer, ITunnelListener
38 {
39
40 protected List mTunnels;
41 protected List mMessageConsumers;
42 protected Map mRegisteredCodecs;
43 protected Map mRegisteredPackers;
44 protected boolean mIsInitialized;
45 protected List mTunnelServerListeners;
46
47
48 public AbstractTunnelServer()
49 {
50 mTunnels = new ArrayList();
51 mRegisteredCodecs = new HashMap();
52 mRegisteredPackers = new HashMap();
53 mMessageConsumers = new ArrayList();
54 mTunnelServerListeners = new ArrayList();
55
56 this.registerCodec(SerializeCodec.class);
57 this.registerPacker(ZipPacker.class);
58 this.registerPacker(CRCPacker.class);
59 this.registerPacker(ScramblePacker.class);
60 }
61
62
63
64 /***
65 * Initializes the ITunnelServer. This method must be called before connections
66 * can be accepted.
67 */
68 public synchronized void initialize()
69 throws IllegalStateException, TunnelException
70 {
71 if (mIsInitialized)
72 throw new IllegalStateException("The tunnel is initialized");
73
74 mIsInitialized = true;
75 }
76
77 /***
78 * Performs cleanup for this ITunnelServer. This involves closing all connections.
79 * No connections can be accepted after this method has been called.
80 */
81 public synchronized void finalize()
82 throws IllegalStateException, TunnelException
83 {
84 if (!mIsInitialized)
85 throw new IllegalStateException("The tunnel is not initialized");
86
87 for (int i = 0; i < mTunnels.size(); i++)
88 try
89 {
90 ((ITunnel) mTunnels.get(i)).finalize();
91 }
92 catch (Exception e)
93 {
94 Log.printError(this, "Coludn't finalize tunnel", e);
95 }
96 mIsInitialized = false;
97 }
98
99 /***
100 * Registers an ITunnelPacker that can be used when setting up a connection.
101 */
102 public synchronized void registerPacker(Class packer)
103 {
104 if (!ITunnelPacker.class.isAssignableFrom(packer))
105 throw new IllegalArgumentException("Packer is not an ITunnelPacker");
106 try
107 {
108 packer.getConstructor(new Class[0]);
109 }
110 catch (NoSuchMethodException e)
111 {
112 Log.printError(this, "Couldn't find any default constructor for packer", e);
113 throw new IllegalArgumentException("Packer has no default constructor");
114 }
115 mRegisteredPackers.put(packer.getName(), packer);
116 }
117
118 /***
119 * Registers an ITunnelCodec that can be used when setting up a connection.
120 */
121 public synchronized void registerCodec(Class codec)
122 {
123 if (!ITunnelCodec.class.isAssignableFrom(codec))
124 throw new IllegalArgumentException("Codec is not an ITunnelCodec");
125 try
126 {
127 codec.getConstructor(new Class[0]);
128 }
129 catch (NoSuchMethodException e)
130 {
131 Log.printError(this, "Couldn't find any default constructor for codec", e);
132 throw new IllegalArgumentException("Codec has no default constructor");
133 }
134 mRegisteredCodecs.put(codec.getName(), codec);
135 }
136
137 /***
138 * Adds the IMessageConsumer that receives messages from all connections that
139 * this ITunnelServer has set up. This is a convenience method. Calling this
140 * method has the same effect as calling addMessageConsumer on all of the
141 * individual ITunnels returned by getTunnels. All IMessageConsumers that have
142 * been added with this method will automatically be added to all new ITunnels
143 * that are create.
144 */
145 public synchronized void addMessageConsumer(IMessageConsumer consumer)
146 {
147 for (int i = 0; i < mTunnels.size(); i++)
148 ((ITunnel) mTunnels.get(i)).addMessageConsumer(consumer);
149
150 mMessageConsumers.add(consumer);
151 }
152
153 /***
154 * Removes the IMessageConsumer all connections that this ITunnelServer has
155 * set up. This is a convenience method. Calling this method has the same
156 * effect as calling removeMessageConsumer on all of the individual ITunnels
157 * returned by getTunnels.
158 */
159 public synchronized void removeMessageConsumer(IMessageConsumer consumer)
160 {
161 for (int i = 0; i < mTunnels.size(); i++)
162 ((ITunnel) mTunnels.get(i)).remomveMessageConsumer(consumer);
163
164 mMessageConsumers.remove(consumer);
165 }
166
167 /***
168 * Returns the ITunnel with the provided index.
169 */
170 public synchronized ITunnel getTunnel(int index)
171 {
172 if (index >= 0 && index < mTunnels.size())
173 return (ITunnel) mTunnels.get(index);
174 return null;
175 }
176
177 /***
178 * Returns an Iterator for all ITunnels that this ITunnelServer has created.
179 */
180 public synchronized Iterator getTunnels()
181 {
182 return mTunnels.iterator();
183 }
184
185 /***
186 * Returns the number of ITunnels that this ITunnelServer has created.
187 */
188 public synchronized int getTunnelCount()
189 {
190 return mTunnels.size();
191 }
192
193 public void addTunnelServerListener(ITunnelServerListener listener)
194 {
195 mTunnelServerListeners.add(listener);
196 }
197
198 public void removeTunnelServerListener(ITunnelServerListener listener)
199 {
200 mTunnelServerListeners.remove(listener);
201 }
202
203
204
205 /***
206 * Invoked when the ITunnel has been closed. This happens on the server side
207 * when the tunnel on the client side is closed.
208 * The source ITunnel is finalized before this method is invoked.
209 */
210 public void tunnelClosed(TunnelEvent event)
211 {
212 this.removeTunnel(event.getSourceTunnel());
213 }
214
215 /***
216 * Invoked on an ITunnel on the client side when the connection to the server
217 * has been lost.
218 * The source ITunnel is finalized before this method is invoked.
219 */
220 public void connectionLost(TunnelEvent event)
221 {
222 this.removeTunnel(event.getSourceTunnel());
223 }
224
225
226 protected synchronized void addTunnel(ITunnel tunnel)
227 {
228 Log.print(this, "Tunnel added");
229
230 mTunnels.add(tunnel);
231 tunnel.addTunnelListener(this);
232
233 for (int i = 0; i < mMessageConsumers.size(); i++)
234 tunnel.addMessageConsumer((IMessageConsumer) mMessageConsumers.get(i));
235
236 this.fireTunnelAddedEvent(tunnel);
237 }
238
239 protected synchronized void removeTunnel(ITunnel tunnel)
240 {
241 Log.print(this, "Tunnel removed");
242
243 if (mTunnels.contains(tunnel))
244 {
245 mTunnels.remove(tunnel);
246 this.fireTunnelRemovedEvent(tunnel);
247 }
248 }
249
250 protected synchronized ITunnelCodec getCodec(String codecClassName)
251 {
252 ITunnelCodec codec = null;
253 Class codecClass = (Class) mRegisteredCodecs.get(codecClassName);
254 if (codecClass == null)
255 return null;
256
257 try
258 {
259 codec = (ITunnelCodec) codecClass.newInstance();
260 }
261 catch (Exception e)
262 {
263 Log.printError(this, "Couldn't create codec instance", e);
264 throw new IllegalStateException("Couldn't create codec instance");
265 }
266
267 return codec;
268 }
269
270 protected synchronized ITunnelPacker getPacker(String packerClassName)
271 {
272 ITunnelPacker packer = null;
273 Class packerClass = (Class) mRegisteredPackers.get(packerClassName);
274 if (packerClass == null)
275 return null;
276
277 try
278 {
279 packer = (ITunnelPacker) packerClass.newInstance();
280 }
281 catch (Exception e)
282 {
283 Log.printError(this, "Couldn't create packer instance", e);
284 throw new IllegalStateException("Couldn't create packer instance");
285 }
286
287 return packer;
288 }
289
290
291 protected void fireTunnelAddedEvent(ITunnel tunnel)
292 {
293 TunnelServerEvent event = new TunnelServerEvent(this, TunnelServerEvent.TUNNEL_ADDED, tunnel);
294 for (int i = 0; i < mTunnelServerListeners.size(); i++)
295 ((ITunnelServerListener) mTunnelServerListeners.get(i)).tunnelAdded(event);
296 }
297
298 protected void fireTunnelRemovedEvent(ITunnel tunnel)
299 {
300 TunnelServerEvent event = new TunnelServerEvent(this, TunnelServerEvent.TUNNEL_REMOVED, tunnel);
301 for (int i = 0; i < mTunnelServerListeners.size(); i++)
302 ((ITunnelServerListener) mTunnelServerListeners.get(i)).tunnelRemoved(event);
303 }
304
305 /***
306 * Try to set up the provided ITunnel based on the information contined
307 * in the connection message. If the tunnel was set up successfully it will
308 * be added to this tunnel server. The invoker of this method is responsible
309 * for calling initialize on the tunnel.
310 *
311 * @return a status message that is to be returned by the invoker of this method.
312 */
313 protected void setUpTunnel(Object connectionMessage, ITunnel tunnel)
314 throws TunnelException
315 {
316 try
317 {
318 if (connectionMessage instanceof AbstractTunnel.IConnectionMessage)
319 {
320
321 ITunnelCodec codec = this.getCodec(((AbstractTunnel.IConnectionMessage) connectionMessage).getCodecClassName());
322 String[] packerClassNames = ((AbstractTunnel.IConnectionMessage) connectionMessage).getPackerClassNames();
323 ITunnelPacker[] packers = new ITunnelPacker[packerClassNames.length];
324 for (int i = 0; i < packers.length; i++)
325 packers[i] = this.getPacker(packerClassNames[i]);
326
327 if (codec != null)
328 {
329 tunnel.setCodec(codec);
330
331
332 for (int i = 0; i < packers.length; i++)
333 if (packers[i] != null)
334 tunnel.addPacker(packers[i]);
335 else
336 throw new TunnelException("Unrecongnized packer: " + packerClassNames[i]);
337
338
339 addTunnel(tunnel);
340 }
341 else
342 throw new TunnelException("Unrecongnized codec: " + ((AbstractTunnel.IConnectionMessage) connectionMessage).getCodecClassName());
343 }
344 else
345 throw new TunnelException("Invalid format of connection message");
346 }
347 catch (Exception e)
348 {
349 Log.printError(this, "Couldn't set up tunnel", e);
350 throw new TunnelException("Couldn't set up tunnel: " + e.getMessage());
351 }
352 }
353
354
355 }