PageRenderTime 22ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/hazelcast-client-legacy/src/main/java/com/hazelcast/client/spi/impl/ClusterListenerSupport.java

https://gitlab.com/vipul.tiwari/hazelcast
Java | 288 lines | 237 code | 35 blank | 16 comment | 16 complexity | 01f25b21da8bb29861d03f0950f4e07a MD5 | raw file
  1. /*
  2. * Copyright (c) 2008-2015, 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. package com.hazelcast.client.spi.impl;
  17. import com.hazelcast.client.AuthenticationException;
  18. import com.hazelcast.client.config.ClientNetworkConfig;
  19. import com.hazelcast.client.connection.AddressProvider;
  20. import com.hazelcast.client.connection.Authenticator;
  21. import com.hazelcast.client.connection.ClientConnectionManager;
  22. import com.hazelcast.client.connection.nio.ClientConnection;
  23. import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
  24. import com.hazelcast.client.impl.LifecycleServiceImpl;
  25. import com.hazelcast.client.impl.client.AuthenticationRequest;
  26. import com.hazelcast.client.impl.client.ClientPrincipal;
  27. import com.hazelcast.client.spi.ClientClusterService;
  28. import com.hazelcast.client.spi.ClientExecutionService;
  29. import com.hazelcast.core.LifecycleEvent;
  30. import com.hazelcast.core.Member;
  31. import com.hazelcast.internal.serialization.SerializationService;
  32. import com.hazelcast.logging.ILogger;
  33. import com.hazelcast.logging.Logger;
  34. import com.hazelcast.nio.Address;
  35. import com.hazelcast.nio.Connection;
  36. import com.hazelcast.nio.ConnectionListener;
  37. import com.hazelcast.nio.serialization.Data;
  38. import com.hazelcast.security.Credentials;
  39. import com.hazelcast.spi.impl.SerializableList;
  40. import com.hazelcast.util.Clock;
  41. import com.hazelcast.util.ExceptionUtil;
  42. import com.hazelcast.util.executor.PoolExecutorThreadFactory;
  43. import java.io.IOException;
  44. import java.net.InetSocketAddress;
  45. import java.util.Collection;
  46. import java.util.Collections;
  47. import java.util.HashSet;
  48. import java.util.Iterator;
  49. import java.util.LinkedList;
  50. import java.util.List;
  51. import java.util.Set;
  52. import java.util.concurrent.ExecutorService;
  53. import java.util.concurrent.Executors;
  54. import java.util.concurrent.Future;
  55. import java.util.concurrent.TimeUnit;
  56. import java.util.logging.Level;
  57. import static com.hazelcast.client.config.ClientProperty.SHUFFLE_MEMBER_LIST;
  58. public abstract class ClusterListenerSupport implements ConnectionListener, ConnectionHeartbeatListener, ClientClusterService {
  59. private static final ILogger LOGGER = Logger.getLogger(ClusterListenerSupport.class);
  60. private static final long TERMINATE_TIMEOUT_SECONDS = 30;
  61. protected final HazelcastClientInstanceImpl client;
  62. private final Collection<AddressProvider> addressProviders;
  63. private final ManagerAuthenticator managerAuthenticator = new ManagerAuthenticator();
  64. private final ExecutorService clusterExecutor;
  65. private final boolean shuffleMemberList;
  66. private Credentials credentials;
  67. private ClientConnectionManager connectionManager;
  68. private ClientMembershipListener clientMembershipListener;
  69. private volatile Address ownerConnectionAddress;
  70. private volatile ClientPrincipal principal;
  71. public ClusterListenerSupport(HazelcastClientInstanceImpl client, Collection<AddressProvider> addressProviders) {
  72. this.client = client;
  73. this.addressProviders = addressProviders;
  74. this.shuffleMemberList = client.getClientProperties().getBoolean(SHUFFLE_MEMBER_LIST);
  75. this.clusterExecutor = createSingleThreadExecutorService(client);
  76. }
  77. private ExecutorService createSingleThreadExecutorService(HazelcastClientInstanceImpl client) {
  78. ThreadGroup threadGroup = client.getThreadGroup();
  79. ClassLoader classLoader = client.getClientConfig().getClassLoader();
  80. PoolExecutorThreadFactory threadFactory =
  81. new PoolExecutorThreadFactory(threadGroup, client.getName() + ".cluster-", classLoader);
  82. return Executors.newSingleThreadExecutor(threadFactory);
  83. }
  84. protected void init() {
  85. this.connectionManager = client.getConnectionManager();
  86. this.clientMembershipListener = new ClientMembershipListener(client);
  87. connectionManager.addConnectionListener(this);
  88. connectionManager.addConnectionHeartbeatListener(this);
  89. credentials = client.getCredentials();
  90. }
  91. public Address getOwnerConnectionAddress() {
  92. return ownerConnectionAddress;
  93. }
  94. public void shutdown() {
  95. clusterExecutor.shutdown();
  96. try {
  97. boolean success = clusterExecutor.awaitTermination(TERMINATE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
  98. if (!success) {
  99. LOGGER.warning("ClientClusterService shutdown could not completed in "
  100. + TERMINATE_TIMEOUT_SECONDS + " seconds");
  101. }
  102. } catch (InterruptedException e) {
  103. LOGGER.warning("ClientClusterService shutdown is interrupted", e);
  104. }
  105. }
  106. private class ManagerAuthenticator implements Authenticator {
  107. @Override
  108. public void authenticate(ClientConnection connection) throws AuthenticationException, IOException {
  109. final SerializationService ss = client.getSerializationService();
  110. AuthenticationRequest auth = new AuthenticationRequest(credentials, principal);
  111. connection.init();
  112. auth.setOwnerConnection(true);
  113. //contains remoteAddress and principal
  114. SerializableList collectionWrapper;
  115. final ClientInvocation clientInvocation = new ClientInvocation(client, auth, connection);
  116. final Future<SerializableList> future = clientInvocation.invoke();
  117. try {
  118. collectionWrapper = ss.toObject(future.get());
  119. } catch (Exception e) {
  120. throw ExceptionUtil.rethrow(e, IOException.class);
  121. }
  122. final Iterator<Data> iter = collectionWrapper.iterator();
  123. final Data addressData = iter.next();
  124. final Address address = ss.toObject(addressData);
  125. connection.setRemoteEndpoint(address);
  126. connection.setIsAuthenticatedAsOwner();
  127. final Data principalData = iter.next();
  128. principal = ss.toObject(principalData);
  129. }
  130. }
  131. protected void connectToCluster() throws Exception {
  132. connectToOne();
  133. clientMembershipListener.listenMembershipEvents(ownerConnectionAddress);
  134. }
  135. private Collection<InetSocketAddress> getSocketAddresses() {
  136. final List<InetSocketAddress> socketAddresses = new LinkedList<InetSocketAddress>();
  137. Collection<Member> memberList = getMemberList();
  138. for (Member member : memberList) {
  139. socketAddresses.add(member.getSocketAddress());
  140. }
  141. for (AddressProvider addressProvider : addressProviders) {
  142. socketAddresses.addAll(addressProvider.loadAddresses());
  143. }
  144. if (shuffleMemberList) {
  145. Collections.shuffle(socketAddresses);
  146. }
  147. return socketAddresses;
  148. }
  149. public ClientPrincipal getPrincipal() {
  150. return principal;
  151. }
  152. private void connectToOne() throws Exception {
  153. ownerConnectionAddress = null;
  154. final ClientNetworkConfig networkConfig = client.getClientConfig().getNetworkConfig();
  155. final int connAttemptLimit = networkConfig.getConnectionAttemptLimit();
  156. final int connectionAttemptPeriod = networkConfig.getConnectionAttemptPeriod();
  157. final int connectionAttemptLimit = connAttemptLimit == 0 ? Integer.MAX_VALUE : connAttemptLimit;
  158. int attempt = 0;
  159. Set<InetSocketAddress> triedAddresses = new HashSet<InetSocketAddress>();
  160. while (attempt < connectionAttemptLimit) {
  161. if (!client.getLifecycleService().isRunning()) {
  162. if (LOGGER.isFinestEnabled()) {
  163. LOGGER.finest("Giving up on retrying to connect to cluster since client is shutdown");
  164. }
  165. break;
  166. }
  167. attempt++;
  168. final long nextTry = Clock.currentTimeMillis() + connectionAttemptPeriod;
  169. boolean isConnected = connect(triedAddresses);
  170. if (isConnected) {
  171. return;
  172. }
  173. final long remainingTime = nextTry - Clock.currentTimeMillis();
  174. LOGGER.warning(
  175. String.format("Unable to get alive cluster connection, try in %d ms later, attempt %d of %d.",
  176. Math.max(0, remainingTime), attempt, connectionAttemptLimit));
  177. if (remainingTime > 0) {
  178. try {
  179. Thread.sleep(remainingTime);
  180. } catch (InterruptedException e) {
  181. break;
  182. }
  183. }
  184. }
  185. throw new IllegalStateException("Unable to connect to any address in the config! "
  186. + "The following addresses were tried:" + triedAddresses);
  187. }
  188. private boolean connect(Set<InetSocketAddress> triedAddresses) throws Exception {
  189. final Collection<InetSocketAddress> socketAddresses = getSocketAddresses();
  190. for (InetSocketAddress inetSocketAddress : socketAddresses) {
  191. try {
  192. triedAddresses.add(inetSocketAddress);
  193. Address address = new Address(inetSocketAddress);
  194. if (LOGGER.isFinestEnabled()) {
  195. LOGGER.finest("Trying to connect to " + address);
  196. }
  197. ClientConnection connection =
  198. (ClientConnection) connectionManager.getOrConnect(address, managerAuthenticator);
  199. if (!connection.isAuthenticatedAsOwner()) {
  200. managerAuthenticator.authenticate(connection);
  201. }
  202. fireConnectionEvent(LifecycleEvent.LifecycleState.CLIENT_CONNECTED);
  203. ownerConnectionAddress = connection.getEndPoint();
  204. return true;
  205. } catch (Exception e) {
  206. Level level = e instanceof AuthenticationException ? Level.WARNING : Level.FINEST;
  207. LOGGER.log(level, "Exception during initial connection to " + inetSocketAddress, e);
  208. }
  209. }
  210. return false;
  211. }
  212. private void fireConnectionEvent(final LifecycleEvent.LifecycleState state) {
  213. ClientExecutionService executionService = client.getClientExecutionService();
  214. executionService.execute(new Runnable() {
  215. @Override
  216. public void run() {
  217. final LifecycleServiceImpl lifecycleService = (LifecycleServiceImpl) client.getLifecycleService();
  218. lifecycleService.fireLifecycleEvent(state);
  219. }
  220. });
  221. }
  222. @Override
  223. public void connectionAdded(Connection connection) {
  224. }
  225. @Override
  226. public void connectionRemoved(Connection connection) {
  227. if (connection.getEndPoint().equals(ownerConnectionAddress)) {
  228. if (client.getLifecycleService().isRunning()) {
  229. clusterExecutor.execute(new Runnable() {
  230. @Override
  231. public void run() {
  232. try {
  233. fireConnectionEvent(LifecycleEvent.LifecycleState.CLIENT_DISCONNECTED);
  234. connectToCluster();
  235. } catch (Exception e) {
  236. LOGGER.warning("Could not re-connect to cluster shutting down the client", e);
  237. client.getLifecycleService().shutdown();
  238. }
  239. }
  240. });
  241. }
  242. }
  243. }
  244. @Override
  245. public void heartBeatStarted(Connection connection) {
  246. }
  247. @Override
  248. public void heartBeatStopped(Connection connection) {
  249. if (connection.getEndPoint().equals(ownerConnectionAddress)) {
  250. connectionManager.destroyConnection(connection);
  251. }
  252. }
  253. }