/*--- formatted by Jindent 2.1, (www.c-lab.de/~jindent) ---*/ /** * *************************************************************** * The LEAP libraries, when combined with certain JADE platform components, * provide a run-time environment for enabling FIPA agents to execute on * lightweight devices running Java. LEAP and JADE teams have jointly * designed the API for ease of integration and hence to take advantage * of these dual developments and extensions so that users only see * one development platform and a * single homogeneous set of APIs. Enabling deployment to a wide range of * devices whilst still having access to the full development * environment and functionalities that JADE provides. * Copyright (C) 2001 Telecom Italia LAB S.p.A. * Copyright (C) 2001 Motorola. * * GNU Lesser General Public License * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * ************************************************************** */ package jade.imtp.leap.JICP; //#MIDP_EXCLUDE_FILE import jade.mtp.TransportAddress; import java.io.*; import jade.imtp.leap.*; import jade.util.leap.*; import jade.imtp.leap.http.HTTPProtocol; /** * @author Giovanni Caire - TILAB */ class ConnectionPool { private HashMap connections = new HashMap(); private TransportProtocol myProtocol; private ConnectionFactory myFactory; private int maxSize; private int size; private boolean closed = false; private long hitCnt = 0; private long missCnt = 0; ConnectionPool(TransportProtocol p, ConnectionFactory f, int ms) { myProtocol = p; myFactory = f; // Temporary hack for HTTP since HTTP connections cannot be re-used if (myProtocol instanceof HTTPProtocol) { maxSize = 0; } else { maxSize = ms; } size = 0; } // The actual connection creation operation must NOT be included in the synchronized block. In facts // in certain cases it may take a lot of time due to TCP timeouts expiration. ConnectionWrapper acquire(TransportAddress ta, boolean requireFreshConnection) throws ICPException { ConnectionWrapper cw = null; List l = null; String url = myProtocol.addrToString(ta); synchronized (this) { if (closed) { throw new ICPException("Pool closed"); } l = (List) connections.get(url); if (l == null) { l = new ArrayList(); connections.put(url, l); } if (requireFreshConnection) { // We are checking a given destination. This means that this destination may be no longer valid // --> In order to avoid keeping invalid connections that can lead to very long waiting times, // close all non-used connections towards this destination. closeConnections(l); } else { Iterator it = l.iterator(); while (it.hasNext()) { cw = (ConnectionWrapper) it.next(); if (cw.lock()) { cw.setReused(); hitCnt++; return cw; } } } } // If we get here no connection is available --> create a new one try { Connection c = myFactory.createConnection(ta); synchronized (this) { cw = new ConnectionWrapper(c, ta); if (size < maxSize) { // Reusable connection --> Store it l.add(cw); size++; } else { // OneShot connection --> don't even store it. cw.setOneShot(); } missCnt++; return cw; } } catch (IOException ioe) { throw new ICPException("Error creating connection. ", ioe); } finally { // We may have created a new list of connections that end up to be useless (e.g. because the connection is one-shot, // or because there was an error creating the connection) --> remove it synchronized (this) { if (l.isEmpty()) { connections.remove(url); } } } } private void closeConnections(List l) { List closedConnections = new ArrayList(); Iterator it = l.iterator(); while (it.hasNext()) { ConnectionWrapper cw = (ConnectionWrapper) it.next(); if (cw.lock()) { cw.close(); cw.unlock(); closedConnections.add(cw); } } // Now remove all closed connections it = closedConnections.iterator(); while (it.hasNext()) { if (l.remove(it.next())) { size--; } } } synchronized void release(ConnectionWrapper cw) { cw.unlock(); } synchronized void remove(ConnectionWrapper cw) { try { String url = myProtocol.addrToString(cw.getDestAddress()); List l = (List) connections.get(url); if (l != null) { if (l.remove(cw)) { size--; if (l.isEmpty()) { connections.remove(url); } } } cw.getConnection().close(); } catch (Exception e) { // Just ignore it } } synchronized void shutdown() { Iterator it = connections.values().iterator(); while (it.hasNext()) { List l = (List) it.next(); for (int i = 0; i < l.size(); i++) { ConnectionWrapper cw = (ConnectionWrapper) l.get(i); cw.close(); } l.clear(); } connections.clear(); closed = true; } void clearExpiredConnections(long currentTime) { Iterator it = getConnectionsList().iterator(); while (it.hasNext()) { ConnectionWrapper cw = (ConnectionWrapper) it.next(); if (cw.isExpired(currentTime)) { remove(cw); cw.unlock(); } } } public String toString() { return "[Connection-pool: total-hit="+hitCnt+", total-miss="+missCnt+", current-size="+size+" connections="+connections+"]"; } private synchronized List getConnectionsList() { List cc = new ArrayList(); Iterator it = connections.values().iterator(); while (it.hasNext()) { List l = (List) it.next(); Iterator it1 = l.iterator(); while (it1.hasNext()) { cc.add(it1.next()); } } return cc; } }