EasConnectionCache.java revision 9383babdbd7c0049a0eb238819a5d9737232e8ec
1package com.android.exchange.eas;
2
3import android.content.Context;
4
5import com.android.emailcommon.provider.HostAuth;
6import com.android.emailcommon.utility.EmailClientConnectionManager;
7import com.android.exchange.Eas;
8import com.android.mail.utils.LogUtils;
9
10import org.apache.http.conn.params.ConnManagerPNames;
11import org.apache.http.conn.params.ConnPerRoute;
12import org.apache.http.conn.routing.HttpRoute;
13import org.apache.http.params.BasicHttpParams;
14import org.apache.http.params.HttpParams;
15
16import java.util.HashMap;
17
18/**
19 * Manage all {@link EmailClientConnectionManager}s used by Exchange operations.
20 * When making connections for persisted accounts, this class will cache and reuse connections
21 * as much as possible. All access of connection objects should accordingly go through this class.
22 *
23 * We use {@link HostAuth}'s id as the cache key. Multiple calls to {@link #getConnectionManager}
24 * with {@link HostAuth} objects with the same id will get the same connection object returned,
25 * i.e. we assume that the rest of the contents of the {@link HostAuth} objects are also the same,
26 * not just the id. If the {@link HostAuth} changes or is deleted, {@link #uncacheConnectionManager}
27 * must be called.
28 *
29 * This cache is a singleton since the whole point is to not have multiples.
30 */
31public class EasConnectionCache {
32
33    private final HashMap<Long, EmailClientConnectionManager> mConnectionMap;
34
35    private static final ConnPerRoute sConnPerRoute = new ConnPerRoute() {
36        @Override
37        public int getMaxForRoute(final HttpRoute route) {
38            return 8;
39        }
40    };
41
42    /** The singleton instance of the cache. */
43    private static EasConnectionCache sCache = null;
44
45    /** Accessor for the cache singleton. */
46    public static EasConnectionCache instance() {
47        if (sCache == null) {
48            sCache = new EasConnectionCache();
49        }
50        return sCache;
51    }
52
53    private EasConnectionCache() {
54        mConnectionMap = new HashMap<Long, EmailClientConnectionManager>();
55    }
56
57    /**
58     * Create an {@link EmailClientConnectionManager} for this {@link HostAuth}.
59     * @param context The {@link Context}.
60     * @param hostAuth The {@link HostAuth} to which we want to connect.
61     * @return The {@link EmailClientConnectionManager} for hostAuth.
62     */
63    private EmailClientConnectionManager createConnectionManager(final Context context,
64            final HostAuth hostAuth) {
65        LogUtils.i(Eas.LOG_TAG, "Creating connection for HostAuth %d", hostAuth.mId);
66        final HttpParams params = new BasicHttpParams();
67        params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 25);
68        params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, sConnPerRoute);
69        return EmailClientConnectionManager.newInstance(context, params, hostAuth);
70    }
71
72    /**
73     * Get the correct {@link EmailClientConnectionManager} for a {@link HostAuth} from our cache.
74     * If it's not in the cache, create and add it.
75     * @param context The {@link Context}.
76     * @param hostAuth The {@link HostAuth} to which we want to connect.
77     * @return The {@link EmailClientConnectionManager} for hostAuth.
78     */
79    private synchronized EmailClientConnectionManager getCachedConnectionManager(
80            final Context context, final HostAuth hostAuth) {
81        LogUtils.i(Eas.LOG_TAG, "Reusing cached connection for HostAuth %d", hostAuth.mId);
82        EmailClientConnectionManager connectionManager = mConnectionMap.get(hostAuth.mId);
83        if (connectionManager == null) {
84            connectionManager = createConnectionManager(context, hostAuth);
85            mConnectionMap.put(hostAuth.mId, connectionManager);
86        }
87        return connectionManager;
88    }
89
90    /**
91     * Get the correct {@link EmailClientConnectionManager} for a {@link HostAuth}. If the
92     * {@link HostAuth} is persistent, then use the cache for this request.
93     * @param context The {@link Context}.
94     * @param hostAuth The {@link HostAuth} to which we want to connect.
95     * @return The {@link EmailClientConnectionManager} for hostAuth.
96     */
97    public EmailClientConnectionManager getConnectionManager(
98            final Context context, final HostAuth hostAuth) {
99        final EmailClientConnectionManager connectionManager;
100        // We only cache the connection manager for persisted HostAuth objects, i.e. objects
101        // whose ids are permanent and won't get reused by other transient HostAuth objects.
102        if (hostAuth.isSaved()) {
103            connectionManager = getCachedConnectionManager(context, hostAuth);
104        } else {
105            connectionManager = createConnectionManager(context, hostAuth);
106        }
107        return connectionManager;
108    }
109
110    /**
111     * Remove a connection manager from the cache. This is necessary when a {@link HostAuth} is
112     * redirected or otherwise altered. It's not strictly necessary but good to also call this
113     * when a {@link HostAuth} is deleted, i.e. when an account is removed.
114     * @param hostAuth The {@link HostAuth} whose connection manager should be deleted.
115     */
116    public synchronized void uncacheConnectionManager(final HostAuth hostAuth) {
117        LogUtils.i(Eas.LOG_TAG, "Uncaching connection for HostAuth %d", hostAuth.mId);
118        mConnectionMap.remove(hostAuth.mId);
119    }
120}
121