Ayaka Koshibe
Committed by Madan Jampani

Refactored ClusterManager as proper fix for Karaf clean issue (Topic phi-fd-on)

Change-Id: Ibb328d73412855dd2d44ca6b734f738ae2996873
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
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 org.onosproject.store.cluster.impl;
17 +
18 +import com.google.common.base.Optional;
19 +import com.google.common.cache.LoadingCache;
20 +import com.google.common.collect.ImmutableSet;
21 +import com.hazelcast.core.IMap;
22 +import com.hazelcast.core.Member;
23 +import com.hazelcast.core.MemberAttributeEvent;
24 +import com.hazelcast.core.MembershipEvent;
25 +import com.hazelcast.core.MembershipListener;
26 +
27 +import org.apache.felix.scr.annotations.Activate;
28 +import org.apache.felix.scr.annotations.Component;
29 +import org.apache.felix.scr.annotations.Deactivate;
30 +import org.apache.felix.scr.annotations.Service;
31 +import org.onosproject.cluster.ClusterEvent;
32 +import org.onosproject.cluster.ClusterStore;
33 +import org.onosproject.cluster.ClusterStoreDelegate;
34 +import org.onosproject.cluster.ControllerNode;
35 +import org.onosproject.cluster.DefaultControllerNode;
36 +import org.onosproject.cluster.NodeId;
37 +import org.onosproject.store.hz.AbsentInvalidatingLoadingCache;
38 +import org.onosproject.store.hz.AbstractHazelcastStore;
39 +import org.onosproject.store.hz.OptionalCacheLoader;
40 +import org.onlab.packet.IpAddress;
41 +
42 +import java.util.Map;
43 +import java.util.Set;
44 +import java.util.concurrent.ConcurrentHashMap;
45 +
46 +import static com.google.common.cache.CacheBuilder.newBuilder;
47 +import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ACTIVATED;
48 +import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_DEACTIVATED;
49 +import static org.onosproject.cluster.ControllerNode.State;
50 +
51 +/**
52 + * Distributed, Hazelcast-based implementation of the cluster nodes store.
53 + */
54 +@Component(immediate = true, enabled = false)
55 +@Service
56 +public class HazelcastClusterStore
57 + extends AbstractHazelcastStore<ClusterEvent, ClusterStoreDelegate>
58 + implements ClusterStore {
59 +
60 + private IMap<byte[], byte[]> rawNodes;
61 + private LoadingCache<NodeId, Optional<DefaultControllerNode>> nodes;
62 +
63 + private String listenerId;
64 + private final MembershipListener listener = new InternalMembershipListener();
65 + private final Map<NodeId, State> states = new ConcurrentHashMap<>();
66 +
67 + private String nodesListenerId;
68 +
69 + @Override
70 + @Activate
71 + public void activate() {
72 + super.activate();
73 + listenerId = theInstance.getCluster().addMembershipListener(listener);
74 +
75 + rawNodes = theInstance.getMap("nodes");
76 + OptionalCacheLoader<NodeId, DefaultControllerNode> nodeLoader
77 + = new OptionalCacheLoader<>(serializer, rawNodes);
78 + nodes = new AbsentInvalidatingLoadingCache<>(newBuilder().build(nodeLoader));
79 + nodesListenerId = rawNodes.addEntryListener(new RemoteCacheEventHandler<>(nodes), true);
80 +
81 + loadClusterNodes();
82 +
83 + log.info("Started");
84 + }
85 +
86 + // Loads the initial set of cluster nodes
87 + private void loadClusterNodes() {
88 + for (Member member : theInstance.getCluster().getMembers()) {
89 + addNode(node(member));
90 + }
91 + }
92 +
93 + @Deactivate
94 + public void deactivate() {
95 + rawNodes.removeEntryListener(nodesListenerId);
96 + theInstance.getCluster().removeMembershipListener(listenerId);
97 + log.info("Stopped");
98 + }
99 +
100 + @Override
101 + public ControllerNode getLocalNode() {
102 + return node(theInstance.getCluster().getLocalMember());
103 + }
104 +
105 + @Override
106 + public Set<ControllerNode> getNodes() {
107 + ImmutableSet.Builder<ControllerNode> builder = ImmutableSet.builder();
108 + for (Optional<DefaultControllerNode> optional : nodes.asMap().values()) {
109 + builder.add(optional.get());
110 + }
111 + return builder.build();
112 + }
113 +
114 + @Override
115 + public ControllerNode getNode(NodeId nodeId) {
116 + return nodes.getUnchecked(nodeId).orNull();
117 + }
118 +
119 + @Override
120 + public State getState(NodeId nodeId) {
121 + State state = states.get(nodeId);
122 + return state == null ? State.INACTIVE : state;
123 + }
124 +
125 + @Override
126 + public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) {
127 + return addNode(new DefaultControllerNode(nodeId, ip, tcpPort));
128 + }
129 +
130 + @Override
131 + public void removeNode(NodeId nodeId) {
132 + synchronized (this) {
133 + rawNodes.remove(serialize(nodeId));
134 + nodes.invalidate(nodeId);
135 + }
136 + }
137 +
138 + // Adds a new node based on the specified member
139 + private synchronized ControllerNode addNode(DefaultControllerNode node) {
140 + rawNodes.put(serialize(node.id()), serialize(node));
141 + nodes.put(node.id(), Optional.of(node));
142 + states.put(node.id(), State.ACTIVE);
143 + return node;
144 + }
145 +
146 + // Creates a controller node descriptor from the Hazelcast member.
147 + private DefaultControllerNode node(Member member) {
148 + IpAddress ip = memberAddress(member);
149 + return new DefaultControllerNode(new NodeId(ip.toString()), ip);
150 + }
151 +
152 + private IpAddress memberAddress(Member member) {
153 + return IpAddress.valueOf(member.getSocketAddress().getAddress());
154 + }
155 +
156 + // Interceptor for membership events.
157 + private class InternalMembershipListener implements MembershipListener {
158 + @Override
159 + public void memberAdded(MembershipEvent membershipEvent) {
160 + log.info("Member {} added", membershipEvent.getMember());
161 + ControllerNode node = addNode(node(membershipEvent.getMember()));
162 + notifyDelegate(new ClusterEvent(INSTANCE_ACTIVATED, node));
163 + }
164 +
165 + @Override
166 + public void memberRemoved(MembershipEvent membershipEvent) {
167 + log.info("Member {} removed", membershipEvent.getMember());
168 + NodeId nodeId = new NodeId(memberAddress(membershipEvent.getMember()).toString());
169 + states.put(nodeId, State.INACTIVE);
170 + notifyDelegate(new ClusterEvent(INSTANCE_DEACTIVATED, getNode(nodeId)));
171 + }
172 +
173 + @Override
174 + public void memberAttributeChanged(MemberAttributeEvent memberAttributeEvent) {
175 + log.info("Member {} attribute {} changed to {}",
176 + memberAttributeEvent.getMember(),
177 + memberAttributeEvent.getKey(),
178 + memberAttributeEvent.getValue());
179 + }
180 + }
181 +}