Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: edu/emory/mathcs/util/net/ConnectionPool.java


1   /* ***** BEGIN LICENSE BLOCK *****
2    * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3    *
4    * The contents of this file are subject to the Mozilla Public License Version
5    * 1.1 (the "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis,
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11   * for the specific language governing rights and limitations under the
12   * License.
13   *
14   * The Original Code is the Emory Utilities.
15   *
16   * The Initial Developer of the Original Code is
17   * The Distributed Computing Laboratory, Emory University.
18   * Portions created by the Initial Developer are Copyright (C) 2002
19   * the Initial Developer. All Rights Reserved.
20   *
21   * Alternatively, the contents of this file may be used under the terms of
22   * either the GNU General Public License Version 2 or later (the "GPL"), or
23   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
24   * in which case the provisions of the GPL or the LGPL are applicable instead
25   * of those above. If you wish to allow use of your version of this file only
26   * under the terms of either the GPL or the LGPL, and not to allow others to
27   * use your version of this file under the terms of the MPL, indicate your
28   * decision by deleting the provisions above and replace them with the notice
29   * and other provisions required by the GPL or the LGPL. If you do not delete
30   * the provisions above, a recipient may use your version of this file under
31   * the terms of any one of the MPL, the GPL or the LGPL.
32   *
33   * ***** END LICENSE BLOCK ***** */
34  
35  package edu.emory.mathcs.util.net;
36  
37  import java.io.IOException;
38  import java.net.Socket;
39  import java.rmi.server.RMIClientSocketFactory;
40  import java.util.HashSet;
41  import java.util.Iterator;
42  
43  /**
44   * Manages a pool of socket connections to a single network endpoint.
45   * Pooling enables reusing connections for multiple, unrelated data transfers,
46   * and it can be used to implement certain connection-based protocols like
47   * HTTP 1.1. Additionally, pooling can aid in controlling network load -
48   * limiting the maximum pool size causes excessive connection requests to
49   * be enqueued at the client side.
50   * <p>
51   * The endpoint is represented by a host name and a port number, as well as
52   * by an optional client socket factory, specified at
53   * the construction time. Client requests connections, use them, then return
54   * them to the pool. Clients should not close the socket associated with
55   * the connection or use the socket after returning connection to the pool.
56   * Upon a request for connection, the pool first tries to
57   * return a pre-existing idle one, creating a new connection only if none
58   * is available.
59   * Request may block if pool size limit is reached and all connections are in
60   * use. After being returned to the pool, if connection idles for longer than
61   * its expiration timeout, it is closed.
62   * <p>
63   * Example:
64   *
65   * <pre>
66   * ConnectionPool pool = new ConnectionPool(host, port);
67   * ...
68   * Connection conn = pool.getConnection();
69   * Socket socket = conn.getSocket();
70   * try {
71   *     socket.getOutputStream().write(0x00);
72   *     ...
73   *     conn.returnToPool();
74   * }
75   * catch (IOException e) {
76   *     conn.close();
77   * }
78   * </pre>
79   *
80   * @author Dawid Kurzyniec
81   * @author Tomasz Janiak
82   * @version 1.0
83   */
84  public class ConnectionPool {
85      static final long DEFAULT_EXPIRATION_TIMEOUT = 15000;
86      static final int DEFAULT_CAPACITY = 10;
87      private final HashSet connections = new HashSet();
88      private final String hostName;
89      private final int port;
90      private final RMIClientSocketFactory socketFactory;
91      final long expirationTimeout;
92      private final int capacity;
93  
94      /**
95       * Creates a connection pool for a specified endpoint, using a default
96       * TCP/IP socket factory, a default expiration timeout of 15 s, and a
97       * default capacity of 10 connections.
98       *
99       * @param hostName remote host name
100      * @param port remote port
101      * @param socketFactory socket factory to use when creating new connections
102      */
103     public ConnectionPool(String hostName, int port) {
104         this(hostName, port, null);
105     }
106 
107     /**
108      * Creates a connection pool for a specified endpoint, using specified
109      * socket factory and a default expiration timeout of 15 s and a
110      * default capacity of 10 connections.
111      *
112      * @param hostName remote host name
113      * @param port remote port
114      * @param socketFactory socket factory to use when creating new connections
115      */
116     public ConnectionPool(String hostName, int port,
117                           RMIClientSocketFactory socketFactory)
118     {
119         this(hostName, port, socketFactory,
120              DEFAULT_EXPIRATION_TIMEOUT, DEFAULT_CAPACITY);
121     }
122 
123     /**
124      * Creates a connection pool for a specified endpoint, using specified
125      * expiration timeout and capacity and a default TCP/IP socket factory.
126      *
127      * @param hostName remote host name
128      * @param port remote port
129      * @param expirationTimeout maximum connection idle time
130      * @param capacity maximum number of active connections
131      */
132     public ConnectionPool(String hostName, int port,
133                           long expirationTimeout, int capacity)
134     {
135         this(hostName, port, null, expirationTimeout, capacity);
136     }
137 
138     /**
139      * Creates a connection pool for a specified endpoint, using specified
140      * socket factory, expiration timeout, and capacity.
141      *
142      * @param hostName remote host name
143      * @param port remote port
144      * @param socketFactory socket factory to use when creating new connections
145      * @param expirationTimeout maximum connection idle time
146      * @param capacity maximum number of active connections
147      */
148     public ConnectionPool(
149         String hostName,
150         int port,
151         RMIClientSocketFactory socketFactory,
152         long expirationTimeout,
153         int capacity)
154     {
155         if (capacity <= 0 || expirationTimeout < 0) {
156             throw new IllegalArgumentException();
157         }
158         this.hostName = hostName;
159         this.port = port;
160         this.socketFactory = socketFactory;
161         this.expirationTimeout = expirationTimeout;
162         this.capacity = capacity;
163     }
164 
165     private Connection findConnection() {
166         Connection result = null;
167         for (Iterator iter = connections.iterator(); iter.hasNext();) {
168             Connection conn = (Connection)iter.next();
169             byte connStatus = conn.acquire();
170             if (connStatus == Connection.READY) {
171                 result = conn;
172                 break;
173             } else if (connStatus == Connection.CLOSED) {
174                 iter.remove();
175             }
176         }
177         return result;
178     }
179 
180     synchronized void notifyConnectionStateChanged() {
181         notify();
182     }
183 
184     /**
185      * Requests a connection from the pool. If an existing idle connection is
186      * found, it is returned. Otherwise, if pool capacity has not been reached,
187      * new connection is created. Otherwise, the operation blocks until
188      * a connection is available.
189      *
190      * @return a connection
191      * @throws IOException if I/O error occurs
192      * @throws InterruptedException if interrupted while waiting for
193      *                              a connection
194      */
195     public synchronized Connection getConnection()
196         throws IOException, InterruptedException
197     {
198         // make sure that connection pooling does not circumvent security
199         // policy by allowing unauthorized clients to use network sockets
200         checkConnectPermission();
201 
202         Connection conn = findConnection();
203         while (conn == null) {
204             if (connections.size() == capacity) {
205                 wait();
206                 conn = findConnection();
207             } else {
208                 Socket socket = socketFactory != null
209                     ? socketFactory.createSocket(hostName, port)
210                     : new Socket(hostName, port);
211                 conn = new Connection(socket, this);
212                 connections.add(conn);
213             }
214         }
215         return conn;
216     }
217 
218     private void checkConnectPermission() {
219         SecurityManager security = System.getSecurityManager();
220         if (security != null) {
221             security.checkConnect(hostName, port);
222         }
223     }
224 }