PageRenderTime 36ms CodeModel.GetById 12ms app.highlight 19ms RepoModel.GetById 2ms app.codeStats 0ms

/hazelcast-client/src/main/java/com/hazelcast/client/ConnectionManager.java

https://bitbucket.org/gabral6_gmailcom/hazelcast
Java | 333 lines | 286 code | 30 blank | 17 comment | 53 complexity | 4b739df0f3014d76d8c9781f730f0d25 MD5 | raw file
  1/*
  2 * Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 *
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 */
 16
 17package com.hazelcast.client;
 18
 19import com.hazelcast.core.Member;
 20import com.hazelcast.core.MembershipEvent;
 21import com.hazelcast.core.MembershipListener;
 22import com.hazelcast.logging.ILogger;
 23import com.hazelcast.logging.Logger;
 24import com.hazelcast.nio.SocketInterceptor;
 25import com.hazelcast.util.Clock;
 26
 27import java.io.IOException;
 28import java.net.InetSocketAddress;
 29import java.util.*;
 30import java.util.concurrent.CopyOnWriteArrayList;
 31import java.util.concurrent.CountDownLatch;
 32import java.util.concurrent.TimeUnit;
 33import java.util.concurrent.atomic.AtomicInteger;
 34import java.util.logging.Level;
 35
 36import static com.hazelcast.core.LifecycleEvent.LifecycleState.*;
 37import static java.text.MessageFormat.format;
 38
 39public class ConnectionManager implements MembershipListener {
 40
 41    private volatile Connection currentConnection;
 42    private final AtomicInteger connectionIdGenerator = new AtomicInteger(-1);
 43    private final List<InetSocketAddress> clusterMembers = new CopyOnWriteArrayList<InetSocketAddress>();
 44    private final List<InetSocketAddress> initialClusterMembers = new CopyOnWriteArrayList<InetSocketAddress>();
 45    private final ILogger logger = Logger.getLogger(getClass().getName());
 46    private final HazelcastClient client;
 47    private volatile int lastDisconnectedConnectionId = -1;
 48    private ClientBinder binder;
 49
 50    private volatile boolean lookingForLiveConnection = false;
 51    private volatile boolean running = true;
 52
 53    private final LifecycleServiceClientImpl lifecycleService;
 54    final Timer heartbeatTimer = new Timer();
 55    private final ClientConfig config;
 56
 57    public ConnectionManager(HazelcastClient client, ClientConfig config, LifecycleServiceClientImpl lifecycleService) {
 58        this.config = config;
 59        this.client = client;
 60        this.lifecycleService = lifecycleService;
 61        this.clusterMembers.addAll(config.getAddressList());
 62        this.initialClusterMembers.addAll(config.getAddressList());
 63        if (config.isShuffle()) {
 64            Collections.shuffle(this.clusterMembers);
 65            Collections.shuffle(this.initialClusterMembers);
 66        }
 67    }
 68
 69    void scheduleHeartbeatTimerTask() {
 70        final int TIMEOUT = config.getConnectionTimeout();
 71        heartbeatTimer.schedule(new TimerTask() {
 72            @Override
 73            public void run() {
 74                long diff = Clock.currentTimeMillis() - client.getInRunnable().lastReceived;
 75                try {
 76                    if (diff >= TIMEOUT / 5 && diff < TIMEOUT) {
 77                        logger.log(Level.FINEST,
 78                                   "Being idle for some time, Doing a getMembers() call to ping the server!");
 79                        final CountDownLatch latch = new CountDownLatch(1);
 80                        new Thread(new Runnable() {
 81                            public void run() {
 82                                Set<Member> members = client.getCluster().getMembers();
 83                                if (members != null && members.size() >= 1) {
 84                                    latch.countDown();
 85                                }
 86                            }
 87                        }).start();
 88                        if (!latch.await(10000, TimeUnit.MILLISECONDS)) {
 89                            logger.log(Level.WARNING, "Server didn't respond to client's ping call within 10 seconds!");
 90                        }
 91                    } else if (diff >= TIMEOUT) {
 92                        logger.log(Level.WARNING, "Server didn't respond to client's requests for " + TIMEOUT / 1000 +
 93                                                  " seconds. Assuming it is dead, closing the connection!");
 94                        currentConnection.close();
 95                    }
 96                } catch (InterruptedException e) {
 97                    return;
 98                } catch (IOException ignored) {
 99                }
100            }
101        }, TIMEOUT, TIMEOUT / 10);
102    }
103
104    public Connection getInitConnection() throws IOException {
105        if (currentConnection == null) {
106            synchronized (this) {
107                currentConnection = lookForLiveConnection(config.getInitialConnectionAttemptLimit(),
108                                                          config.getReConnectionTimeOut());
109            }
110        }
111        return currentConnection;
112    }
113
114    public Connection lookForLiveConnection() throws IOException {
115        return lookForLiveConnection(config.getReconnectionAttemptLimit(), config.getReConnectionTimeOut());
116    }
117
118    private Connection lookForLiveConnection(final int attemptsLimit,
119                                             final int reconnectionTimeout) throws IOException {
120        lookingForLiveConnection = true;
121        try {
122            boolean restored = false;
123            int attempt = 0;
124            while (currentConnection == null && running && !Thread.interrupted()) {
125                final long next = Clock.currentTimeMillis() + reconnectionTimeout;
126                synchronized (this) {
127                    if (currentConnection == null) {
128                        final Connection connection = searchForAvailableConnection();
129                        restored = connection != null;
130                        if (restored) {
131                            try {
132                                ClientConfig clientConfig = client.getClientConfig();
133                                if (clientConfig != null) {
134                                    SocketInterceptor socketInterceptor = clientConfig.getSocketInterceptor();
135                                    if (socketInterceptor != null) {
136                                        socketInterceptor.onConnect(connection.getSocket());
137                                    }
138                                }
139                                bindConnection(connection);
140                                currentConnection = connection;
141                            } catch (Throwable e) {
142                                closeConnection(connection);
143                                logger.log(Level.WARNING, "got an exception on getConnection:" + e.getMessage(), e);
144                                restored = false;
145                            }
146                        }
147                    }
148                }
149                if (currentConnection != null) {
150                    logger.log(Level.FINE, "Client is connecting to " + currentConnection);
151                    lookingForLiveConnection = false;
152                    break;
153                }
154                if (attempt >= attemptsLimit) {
155                    break;
156                }
157                attempt++;
158                final long t = next - Clock.currentTimeMillis();
159                logger.log(Level.INFO, format("Unable to get alive cluster connection," +
160                                              " try in {0} ms later, attempt {1} of {2}.",
161                                              Math.max(0, t), attempt, attemptsLimit));
162                if (t > 0) {
163                    try {
164                        Thread.sleep(t);
165                    } catch (InterruptedException e) {
166                        break;
167                    }
168                }
169            }
170            if (restored) {
171                notifyConnectionIsRestored();
172            }
173        } finally {
174            lookingForLiveConnection = false;
175        }
176        return currentConnection;
177    }
178
179    void closeConnection(final Connection connection) {
180        try {
181            if (connection != null) {
182                connection.close();
183            }
184        } catch (Throwable e) {
185            logger.log(Level.INFO, "got an exception on closeConnection "
186                                   + connection + ":" + e.getMessage(), e);
187        }
188    }
189
190    public Connection getConnection() throws IOException {
191        if (currentConnection == null && running && !lookingForLiveConnection) {
192            boolean restored = false;
193            synchronized (this) {
194                if (currentConnection == null) {
195                    Connection connection = searchForAvailableConnection();
196                    if (connection != null) {
197                        logger.log(Level.FINE, "Client is connecting to " + connection);
198                        try {
199                            bindConnection(connection);
200                            currentConnection = connection;
201                        } catch (Throwable e) {
202                            closeConnection(connection);
203                            logger.log(Level.WARNING, "got an exception on getConnection:" + e.getMessage(), e);
204                        }
205                    }
206                    restored = currentConnection != null;
207                }
208            }
209            if (restored) {
210                notifyConnectionIsRestored();
211            }
212        }
213        return currentConnection;
214    }
215
216    void notifyConnectionIsRestored() {
217        lifecycleService.fireLifecycleEvent(CLIENT_CONNECTION_OPENING);
218    }
219
220    void notifyConnectionIsOpened() {
221        lifecycleService.fireLifecycleEvent(CLIENT_CONNECTION_OPENED);
222    }
223
224    void bindConnection(Connection connection) throws IOException {
225        binder.bind(connection, config.getCredentials());
226    }
227
228    public void destroyConnection(final Connection connection) {
229        boolean lost = false;
230        synchronized (this) {
231            if (currentConnection != null &&
232                connection != null &&
233                currentConnection.getVersion() == connection.getVersion()) {
234                logger.log(Level.WARNING, "Connection to " + currentConnection + " is lost");
235                // remove current connection's address from member list.
236                // if address is IPv6 then remove all possible socket addresses (for all scopes)
237                while (clusterMembers.remove(currentConnection.getAddress())) ;
238                currentConnection = null;
239                lost = true;
240                try {
241                    connection.close();
242                } catch (IOException e) {
243                    logger.log(Level.FINEST, e.getMessage(), e);
244                }
245            }
246        }
247        if (lost) {
248            lifecycleService.fireLifecycleEvent(CLIENT_CONNECTION_LOST);
249        }
250    }
251
252    private void popAndPush(List<InetSocketAddress> clusterMembers) {
253        if (!clusterMembers.isEmpty()) {
254            InetSocketAddress address = clusterMembers.remove(0);
255            clusterMembers.add(address);
256        }
257    }
258
259    private Connection searchForAvailableConnection() {
260        Connection connection = null;
261        popAndPush(clusterMembers);
262        if(clusterMembers.isEmpty()){
263            clusterMembers.addAll(initialClusterMembers);
264        }
265        int counter = clusterMembers.size();
266
267        while (counter > 0) {
268            try {
269                connection = getNextConnection();
270                break;
271            } catch (Exception e) {
272                logger.log(Level.FINEST, e.getMessage(), e);
273                popAndPush(clusterMembers);
274                counter--;
275            }
276        }
277        logger.log(Level.FINEST, format("searchForAvailableConnection connection:{0}", connection));
278        return connection;
279    }
280
281    protected Connection getNextConnection() {
282        InetSocketAddress address = clusterMembers.get(0);
283        return new Connection(config.getConnectionTimeout(), address, connectionIdGenerator.incrementAndGet());
284    }
285
286    public void memberAdded(MembershipEvent membershipEvent) {
287        InetSocketAddress address = membershipEvent.getMember().getInetSocketAddress();
288        Collection<InetSocketAddress> addresses = AddressHelper.getPossibleSocketAddresses(address.getAddress(),
289                                                                                           address.getPort());
290        clusterMembers.addAll(addresses);
291        initialClusterMembers.addAll(addresses);
292    }
293
294    public void memberRemoved(MembershipEvent membershipEvent) {
295        InetSocketAddress address = membershipEvent.getMember().getInetSocketAddress();
296        Collection<InetSocketAddress> addresses = AddressHelper.getPossibleSocketAddresses(address.getAddress(),
297                                                                                           address.getPort());
298        clusterMembers.removeAll(addresses);
299    }
300
301    public void updateMembers() {
302        Set<Member> members = client.getCluster().getMembers();
303        clusterMembers.clear();
304        for (Member member : members) {
305            InetSocketAddress address = member.getInetSocketAddress();
306            Collection<InetSocketAddress> addresses = AddressHelper.getPossibleSocketAddresses(address.getAddress(),
307                                                                                               address.getPort());
308            clusterMembers.addAll(addresses);
309        }
310    }
311
312    public boolean shouldExecuteOnDisconnect(Connection connection) {
313        if (connection == null || lastDisconnectedConnectionId >= connection.getVersion()) {
314            return false;
315        }
316        lastDisconnectedConnectionId = connection.getVersion();
317        return true;
318    }
319
320    public void setBinder(ClientBinder binder) {
321        this.binder = binder;
322    }
323
324    List<InetSocketAddress> getClusterMembers() {
325        return clusterMembers;
326    }
327
328    public void shutdown() {
329        logger.log(Level.INFO, getClass().getSimpleName() + " shutdown");
330        running = false;
331        heartbeatTimer.cancel();
332    }
333}