KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonathan > libs > resources > tcpip > JConnectionMgr


1 /***
2  * Jonathan: an Open Distributed Processing Environment
3  * Copyright (C) 1999-2000 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Release: 3.0
20  *
21  * Contact: jonathan@objectweb.org
22  *
23  * Author: Bruno Dumant
24  *
25  */

26
27 package org.objectweb.jonathan.libs.resources.tcpip;
28
29 import java.io.IOException JavaDoc;
30
31 import org.objectweb.jonathan.apis.kernel.JonathanException;
32 import org.objectweb.jonathan.apis.protocols.ip.IpConnection;
33 import org.objectweb.jonathan.apis.protocols.ip.IpSession;
34 import org.objectweb.jonathan.apis.protocols.ip.TcpIpConnectionMgr;
35 import org.objectweb.jonathan.apis.protocols.ip.TcpIpSrvConnectionFactory;
36 import org.objectweb.jonathan.apis.resources.Chunk;
37
38 /**
39  * Default implementation of a connection manager and factory.
40  */

41 public class JConnectionMgr implements TcpIpConnectionMgr {
42    
43    Connection[] connections = new Connection[101];
44    int connects;
45    SrvConnectionFactory server_connection_factories;
46
47    Connection first_idle;
48    Connection last_idle;
49    int idle;
50    
51    protected TcpIpConnectionMgr factory;
52
53    /**
54     * Maximum number of idle connections kept by this manager.
55     * This constant is defined under the name <code>/jonathan/tcpip/max_idle</code>
56     * in the bootstrap context.
57     */

58    public int max_idle;
59
60    /**
61     * Returns a new connection manager
62     * @param max_idle maximum number of idle connections
63     * @param connection_factory a factory to actually create connections
64     */

65    public JConnectionMgr(int max_idle,TcpIpConnectionMgr connection_factory) {
66       connects = 0;
67       this.max_idle = max_idle;
68       this.factory = connection_factory;
69    }
70
71    /**
72     * Returns the canonical host name of the provided host.
73     * @param hostname a host name
74     * @return the corresponding canonical host name.
75     */

76    public String JavaDoc getCanonicalHostName(String JavaDoc hostname) {
77       return factory.getCanonicalHostName(hostname);
78    }
79    
80    /**
81     * Returns a new client connection.
82     * <p>
83     * This method is called by a protocol.
84     * The protocol provides a session (i.e. an object
85     * representing an abstract communication channel) and expects a connection
86     * (i.e. a communication resource). The returned connection must have been
87     * built using the provided session, or be a connection associated with a
88     * session having the same destination as the provided session.
89     * @param host the host name of the distant server;
90     * @param port the port number of a server socket on that host;
91     * @param session a TcpIp session
92     * @return a connection for that session.
93     * @exception JonathanException if an error occurs.
94     */

95    public synchronized IpConnection newCltConnection(String JavaDoc host, int port,
96                                                      IpSession session)
97       throws JonathanException {
98       host = getCanonicalHostName(host);
99       int hash = host.hashCode() + port;
100       int len = connections.length;
101       int index = (hash & 0x7FFFFFFF) % len;
102       Connection connection = connections[index];
103       while (connection != null) {
104          if (connection.getPort() == port &&
105              connection.getHostName().equals(host)) {
106             if (connection.getSession() == null) {
107                connection.acquire();
108                connection.setSession(session);
109                return connection;
110             } else if (connection.getSession().equals(session)) {
111                connection.acquire();
112                return connection;
113             }
114          }
115          connection = connection.next;
116       }
117       connection =
118          newCltConnection(factory.newCltConnection(host,port,session));
119       Connection first = connections[index];
120       connections[index] = connection;
121       connection.next = first;
122       connects++;
123       if (connects > len / 2) {
124          rehash(len);
125       }
126       return connection;
127    }
128
129    /**
130     * Returns a new server connection factory encapsulating a server socket on the
131     * provided port. If port = 0, an anonymous server socket is opened.
132     * @param port the expected port of the server socket;
133     * @return a server connection factory.
134     * @exception JonathanException if an error occurs.
135     */

136    public TcpIpSrvConnectionFactory newSrvConnectionFactory(int port)
137       throws JonathanException {
138       SrvConnectionFactory fac = server_connection_factories;
139       while (fac != null) {
140          if (fac.getPort() == port) {
141             break;
142          }
143          fac = fac.next;
144       }
145       if (fac == null) {
146          fac = server_connection_factories;
147          server_connection_factories =
148             new SrvConnectionFactory(factory.newSrvConnectionFactory(port));
149          server_connection_factories.next = fac;
150          return server_connection_factories;
151       } else {
152          return fac;
153       }
154    }
155       
156    /**
157     * Builds a new client-side connection encapsulating the provided connection.
158     *
159     * @param connection a tcpip connection.
160     * @return a new client-side connection.
161     * @exception JonathanException JonathanException if something goes wrong.
162     */

163    protected Connection newCltConnection(IpConnection connection)
164       throws JonathanException {
165       return new Connection(connection);
166    }
167    
168    /**
169     * Removes the connection from the set of managed connections.
170     * @param connection the connection to remove.
171     */

172    void remove(Connection connection) {
173       int hash = connection.hashCode();
174       int len = connections.length;
175       int index = (hash & 0x7FFFFFFF) % len;
176       Connection current = connections[index];
177       Connection prev = null;
178       while (current != null) {
179          if (connection == current) {
180             if (prev == null) {
181                connections[index] = current.next;
182             } else {
183                prev.next = current.next;
184             }
185             return;
186          } else {
187             current = current.next;
188          }
189       }
190    }
191
192    void add(Connection connection) {
193       int hash = connection.hashCode();
194       int len = connections.length;
195       int index = (hash & 0x7FFFFFFF) % len;
196       Connection first = connections[index];
197       connections[index] = connection;
198       connection.next = first;
199       connects++;
200       if (connects > len / 2) {
201          rehash(len);
202       }
203    }
204
205    void removeConnectionFactory(SrvConnectionFactory factory) {
206       SrvConnectionFactory connection_factory =
207          server_connection_factories, prev = null;
208       while (connection_factory != null) {
209          if (connection_factory == factory) {
210             if (prev != null) {
211                prev.next = connection_factory.next;
212             } else {
213                server_connection_factories = connection_factory.next;
214             }
215             return;
216          }
217          prev = connection_factory;
218          connection_factory = connection_factory.next;
219       }
220    }
221
222    
223    // rehashes the hash table, if necessary.
224
void rehash(int len) {
225       Connection entry, next_entry, first_entry;
226       int index;
227       int new_len = 2 * len + 1;
228       Connection[] new_table = new Connection[new_len];
229       
230       for (int i = 0; i < len; i++) {
231          entry = connections[i];
232          while (entry != null) {
233             next_entry = entry.next;
234             // rehashing
235
index = (entry.hashCode() & 0x7FFFFFFF) % new_len;
236             first_entry = new_table[index];
237             new_table[index] = entry;
238             entry.next = first_entry;
239             //
240
entry = next_entry;
241          }
242       }
243       connections = new_table;
244    }
245
246    /**
247     * Implementation of TcpIpConnection.
248     */

249    public class Connection implements IpConnection {
250       /** Next connection in the idle list (null if connection is active) */
251       Connection next_idle;
252       /** Previous connection in the idle list (null if connection is active) */
253       Connection prev_idle;
254       /** Number of objects using that connection. */
255       int acquired;
256       /** The next connection in a collision list */
257       Connection next;
258       
259       IpConnection delegate;
260
261       /**
262        * Builds a new connection.
263        *
264        * @param delegate next connection in the idle list (null if connection
265        * is active).
266        */

267       protected Connection(IpConnection delegate) {
268          this.delegate = delegate;
269          acquired = 1;
270       }
271
272       public int available() throws IOException JavaDoc {
273          return delegate.available();
274       }
275       
276       public void receive(Chunk chunk,int to_read) throws IOException JavaDoc {
277          delegate.receive(chunk,to_read);
278       }
279       
280       public void emit(Chunk chunk) throws IOException JavaDoc {
281          delegate.emit(chunk);
282       }
283
284       /**
285        * Returns the port number of the underlying socket.
286        * @return the port number of the underlying socket.
287        */

288       public int getPort() {
289          return delegate.getPort();
290       }
291
292       /**
293        * Returns the host name of the underlying socket.
294        * @return the host name of the underlying socket.
295        */

296       public String JavaDoc getHostName() {
297          return delegate.getHostName();
298       }
299       
300       /**
301        * Returns the session attached to this connection.
302        * @return the session attached to this connection.
303        */

304       public IpSession getSession() {
305          return delegate.getSession();
306       }
307       
308
309       /**
310        * Attaches a new session to this connection.
311        * @param session the session to be attached to the target connection.
312        */

313       public void setSession(IpSession session) {
314          delegate.setSession(session);
315       }
316
317       /**
318        * Deletes this connection, removing it from the connection manager, and
319        * closing the socket. This method should not be used a a socket user unless
320        * a problem occurs on the connection, like an exception when trying to read
321        * or to write data.
322        */

323       public void delete() {
324          synchronized(JConnectionMgr.this) {
325             delegate.delete();
326             withdraw();
327          }
328       }
329    
330       /**
331        * Returns when the socket is acquired. This information is taken into
332        * account by the connection manager to avoid closing connections still in
333        * use.
334        */

335       public void acquire() {
336          synchronized(JConnectionMgr.this) {
337             acquired++;
338             if (acquired == 1) {
339                if (prev_idle != null) {
340                   prev_idle.next_idle = next_idle;
341                } else {
342                   first_idle = next_idle;
343                }
344                if (next_idle != null) {
345                   next_idle.prev_idle = prev_idle;
346                } else {
347                   last_idle = prev_idle;
348                }
349                prev_idle = next_idle = null;
350                idle--;
351             }
352          }
353       }
354    
355       /**
356        * Releases this connection. This is to indicate to the connection manager
357        * that the target connection is no longer used.
358        */

359       public void release() {
360          synchronized(JConnectionMgr.this) {
361             acquired--;
362             if (acquired == 0) {
363                if (last_idle != null) {
364                   last_idle.next_idle = this;
365                   last_idle = this;
366                } else {
367                   last_idle = first_idle = this;
368                }
369                if (idle >= max_idle) {
370                   first_idle.delegate.release();
371                   first_idle.withdraw();
372                }
373                idle++;
374             }
375          }
376       }
377
378       void withdraw() {
379          remove(this);
380          if (next_idle != null) {
381             if (prev_idle != null) {
382                prev_idle.next_idle = next_idle;
383                next_idle.prev_idle = prev_idle;
384             } else {
385                first_idle = next_idle;
386                next_idle.prev_idle = null;
387             }
388             idle--;
389          } else if (prev_idle != null) {
390             last_idle = prev_idle;
391             prev_idle.next_idle = null;
392             idle--;
393          } else if (last_idle == this) {
394             // may occur if max_idle <= 0
395
last_idle = null;
396             prev_idle = null;
397             idle--;
398          }
399       }
400
401       public String JavaDoc toString() {
402          return "JConnectionMgr.Connection" + System.identityHashCode(this)
403             + "[" + delegate + "]";
404       }
405
406       public int hashCode() {
407          int hashcode = delegate.getPort() + delegate.getHostName().hashCode();
408          return hashcode;
409       }
410    }
411
412    class SrvConnectionFactory implements TcpIpSrvConnectionFactory {
413
414       TcpIpSrvConnectionFactory delegate;
415       SrvConnectionFactory next;
416    
417       SrvConnectionFactory(TcpIpSrvConnectionFactory delegate)
418          throws JonathanException {
419          this.delegate = delegate;
420       }
421
422       public IpConnection newSrvConnection(IpSession session)
423          throws JonathanException {
424          return delegate.newSrvConnection(session);
425       }
426    
427       public int getPort() {
428          return delegate.getPort();
429       }
430       
431       public String JavaDoc getHostName() {
432          return delegate.getHostName();
433       }
434       
435       public void close() {
436          synchronized(JConnectionMgr.this) {
437             delegate.close();
438             removeConnectionFactory(this);
439          }
440       }
441    }
442 }
443
444
445
446
447
448
Popular Tags