001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov
021: * @version $Revision: 1.1.2.2 $
022: */package org.apache.harmony.rmi.client;
023:
024: import java.net.Socket;
025: import java.rmi.RemoteException;
026: import java.security.AccessController;
027: import java.util.Collections;
028: import java.util.Enumeration;
029: import java.util.HashSet;
030: import java.util.Hashtable;
031: import java.util.Iterator;
032: import java.util.Set;
033:
034: import org.apache.harmony.rmi.common.CreateThreadAction;
035: import org.apache.harmony.rmi.common.GetLongPropAction;
036: import org.apache.harmony.rmi.common.RMILog;
037: import org.apache.harmony.rmi.common.RMIProperties;
038: import org.apache.harmony.rmi.internal.nls.Messages;
039: import org.apache.harmony.rmi.transport.Endpoint;
040: import org.apache.harmony.rmi.transport.proxy.HttpConnection;
041: import org.apache.harmony.rmi.transport.proxy.HttpOutboundSocket;
042: import org.apache.harmony.rmi.transport.tcp.TcpConnection;
043:
044: /**
045: * Manager managing connections from the client side: it holds the list of
046: * opened connections so the client could reuse them.
047: *
048: * @author Mikhail A. Markov
049: * @version $Revision: 1.1.2.2 $
050: */
051: public final class ClientConnectionManager {
052:
053: // List of active connections
054: private static Hashtable connsTable = new Hashtable();
055:
056: /**
057: * Period during which the connection could be reused
058: * (and after which it's closed).
059: * Default value is 15000 ms.
060: */
061: public static long connTimeout = ((Long) AccessController
062: .doPrivileged(new GetLongPropAction(
063: RMIProperties.CONNECTIONTIMEOUT_PROP, 15000)))
064: .longValue();
065:
066: /** Log for logging tcp connections activity. */
067: public static final RMILog tcpTransportLog = RMILog
068: .getTcpTransportLog();
069:
070: // Starts thread managing expired connections.
071: static {
072: ConnectionsCollector coll = new ConnectionsCollector();
073: ((Thread) AccessController.doPrivileged(new CreateThreadAction(
074: coll, "ConnectionsCollector", true))).start(); //$NON-NLS-1$
075: }
076:
077: /**
078: * Returns 1-st available connection. If there is no available connections
079: * a new one is created.
080: *
081: * @param ep Endpoint to connect to
082: *
083: * @return opened connection
084: *
085: * @throws RemoteException if any error occurred while obtaining connection
086: */
087: public static ClientConnection getConnection(Endpoint ep)
088: throws RemoteException {
089: ClientConnection conn = null;
090:
091: synchronized (connsTable) {
092: Set conns = (Set) connsTable.get(ep);
093:
094: if (conns != null && !conns.isEmpty()) {
095: for (Iterator iter = conns.iterator(); iter.hasNext();) {
096: conn = (ClientConnection) iter.next();
097:
098: if (conn.isReusable() && conn.reuse()) {
099: return conn;
100: }
101: }
102: }
103: }
104: Socket s = ep.createSocket();
105:
106: if (s instanceof HttpOutboundSocket) {
107: conn = new HttpConnection(s, ep);
108: } else {
109: conn = new TcpConnection(s, ep);
110: }
111:
112: synchronized (connsTable) {
113: Set conns = (Set) connsTable.get(ep);
114:
115: if (conns == null) {
116: conns = Collections.synchronizedSet(new HashSet());
117: }
118: conns.add(conn);
119: connsTable.put(ep, conns);
120: }
121: return conn;
122: }
123:
124: /**
125: * Removes connection from the list of connections.
126: *
127: * @param conn connection to be removed
128: */
129: public static void removeConnection(ClientConnection conn) {
130: Endpoint ep = conn.getEndpoint();
131:
132: synchronized (connsTable) {
133: Set conns = (Set) connsTable.get(ep);
134:
135: if (conns == null) {
136: return;
137: }
138: conns.remove(conn);
139:
140: if (conns.size() == 0) {
141: connsTable.remove(ep);
142: }
143: }
144: }
145:
146: /*
147: * Class checking reusable available connections if they are already
148: * expired - and removing them.
149: */
150: private static class ConnectionsCollector implements Runnable {
151:
152: /**
153: * Checks reusable available connections if they are already expired and
154: * removes them.
155: */
156: public void run() {
157: long wakeUpTime;
158:
159: while (true) {
160: wakeUpTime = Long.MAX_VALUE;
161:
162: synchronized (connsTable) {
163: for (Enumeration eps = connsTable.keys(); eps
164: .hasMoreElements();) {
165: Endpoint ep = (Endpoint) eps.nextElement();
166: Set conns = (Set) connsTable.get(ep);
167:
168: if (conns.isEmpty()) {
169: connsTable.remove(ep);
170: continue;
171: }
172:
173: for (Iterator iter = conns.iterator(); iter
174: .hasNext();) {
175: ClientConnection conn = (ClientConnection) iter
176: .next();
177:
178: if (conn.isReusable() && conn.isAvailable()) {
179: long expirTime = conn.getExpiration();
180: long curTime = System
181: .currentTimeMillis();
182:
183: if (expirTime <= curTime) {
184: // connection is expired
185: conn.close(false);
186: iter.remove();
187:
188: if (tcpTransportLog
189: .isLoggable(RMILog.VERBOSE)) {
190: // rmi.log.37={0} connection timeout is expired
191: tcpTransportLog
192: .log(
193: RMILog.VERBOSE,
194: Messages
195: .getString(
196: "rmi.log.37", conn.toString())); //$NON-NLS-1$
197: }
198: continue;
199: }
200: wakeUpTime = Math.min(wakeUpTime,
201: expirTime);
202: }
203: }
204: }
205: }
206: long sleepTime;
207:
208: if (wakeUpTime == Long.MAX_VALUE) {
209: sleepTime = connTimeout;
210: } else {
211: sleepTime = wakeUpTime - System.currentTimeMillis();
212: }
213:
214: try {
215: Thread.sleep(sleepTime);
216: } catch (InterruptedException ie) {
217: }
218: }
219: }
220: }
221: }
|