blob: 31de685283c63b9df34a25afa1af239d97c2d976 [file] [log] [blame]
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -07001package net.onrc.onos.datagrid;
2
3import java.io.FileNotFoundException;
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.HashMap;
7import java.util.Map;
8
9import net.floodlightcontroller.core.IFloodlightProviderService;
10import net.floodlightcontroller.core.module.FloodlightModuleContext;
11import net.floodlightcontroller.core.module.FloodlightModuleException;
12import net.floodlightcontroller.core.module.IFloodlightModule;
13import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavovda7ef612013-10-30 16:12:14 -070014import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavovda7ef612013-10-30 16:12:14 -070015import net.onrc.onos.datagrid.web.DatagridWebRoutable;
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -070016
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070017import org.slf4j.Logger;
18import org.slf4j.LoggerFactory;
19
20import com.hazelcast.config.Config;
21import com.hazelcast.config.FileSystemXmlConfig;
22import com.hazelcast.core.Hazelcast;
23import com.hazelcast.core.HazelcastInstance;
24import com.hazelcast.instance.GroupProperties;
25
26/**
27 * A datagrid service that uses Hazelcast as a datagrid.
28 * The relevant data is stored in the Hazelcast datagrid and shared as
29 * appropriate in a multi-node cluster.
30 */
31public class HazelcastDatagrid implements IFloodlightModule, IDatagridService {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070032 static final Logger log = LoggerFactory.getLogger(HazelcastDatagrid.class);
33 private IRestApiService restApi;
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070034
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070035 static final String HAZELCAST_CONFIG_FILE = "datagridConfig";
36 private HazelcastInstance hazelcastInstance;
37 private Config hazelcastConfig;
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070038
Pavlin Radoslavov07af5f22014-03-21 15:17:58 -070039 //
40 // NOTE: eventChannels is kept thread safe by using explicit "synchronized"
41 // blocks below. Those are needed to protect the integrity of each entry
42 // instance, and avoid preemption during channel creation/startup.
43 //
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070044 private final Map<String, IEventChannel<?, ?>> eventChannels = new HashMap<>();
Pavlin Radoslavov7940b652014-02-13 19:42:05 -080045
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -070046 /**
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070047 * Initialize the Hazelcast Datagrid operation.
48 *
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070049 * @param configFilename the configuration filename.
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070050 */
51 public void init(String configFilename) {
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070052 /*
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070053 System.setProperty("hazelcast.socket.receive.buffer.size", "32");
54 System.setProperty("hazelcast.socket.send.buffer.size", "32");
55 */
56 // System.setProperty("hazelcast.heartbeat.interval.seconds", "100");
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080057
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070058 // Init from configuration file
59 try {
60 hazelcastConfig = new FileSystemXmlConfig(configFilename);
61 } catch (FileNotFoundException e) {
62 log.error("Error opening Hazelcast XML configuration. File not found: " + configFilename, e);
63 }
64 /*
65 hazelcastConfig.setProperty(GroupProperties.PROP_IO_THREAD_COUNT, "1");
66 hazelcastConfig.setProperty(GroupProperties.PROP_OPERATION_THREAD_COUNT, "1");
67 hazelcastConfig.setProperty(GroupProperties.PROP_EVENT_THREAD_COUNT, "1");
68 */
69 //
70 hazelcastConfig.setProperty(GroupProperties.PROP_EVENT_QUEUE_CAPACITY, "4000000");
71 hazelcastConfig.setProperty(GroupProperties.PROP_SOCKET_RECEIVE_BUFFER_SIZE, "4096");
72 hazelcastConfig.setProperty(GroupProperties.PROP_SOCKET_SEND_BUFFER_SIZE, "4096");
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070073 }
74
75 /**
76 * Shutdown the Hazelcast Datagrid operation.
77 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080078 @Override
79 protected void finalize() {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070080 close();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070081 }
82
83 /**
84 * Shutdown the Hazelcast Datagrid operation.
85 */
86 public void close() {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070087 Hazelcast.shutdownAll();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070088 }
89
90 /**
91 * Get the collection of offered module services.
92 *
93 * @return the collection of offered module services.
94 */
95 @Override
96 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080097 Collection<Class<? extends IFloodlightService>> l =
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070098 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070099 l.add(IDatagridService.class);
100 return l;
101 }
102
103 /**
104 * Get the collection of implemented services.
105 *
106 * @return the collection of implemented services.
107 */
108 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800109 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700110 getServiceImpls() {
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700111 Map<Class<? extends IFloodlightService>,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700112 IFloodlightService> m =
113 new HashMap<Class<? extends IFloodlightService>,
114 IFloodlightService>();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700115 m.put(IDatagridService.class, this);
116 return m;
117 }
118
119 /**
120 * Get the collection of modules this module depends on.
121 *
122 * @return the collection of modules this module depends on.
123 */
124 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800125 public Collection<Class<? extends IFloodlightService>>
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700126 getModuleDependencies() {
127 Collection<Class<? extends IFloodlightService>> l =
128 new ArrayList<Class<? extends IFloodlightService>>();
129 l.add(IFloodlightProviderService.class);
130 l.add(IRestApiService.class);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700131 return l;
132 }
133
134 /**
135 * Initialize the module.
136 *
137 * @param context the module context to use for the initialization.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700138 * @throws FloodlightModuleException on error
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700139 */
140 @Override
141 public void init(FloodlightModuleContext context)
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700142 throws FloodlightModuleException {
143 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700144
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700145 // Get the configuration file name and configure the Datagrid
146 Map<String, String> configMap = context.getConfigParams(this);
147 String configFilename = configMap.get(HAZELCAST_CONFIG_FILE);
148 this.init(configFilename);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700149 }
150
151 /**
152 * Startup module operation.
153 *
154 * @param context the module context to use for the startup.
155 */
156 @Override
157 public void startUp(FloodlightModuleContext context) {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700158 hazelcastInstance = Hazelcast.newHazelcastInstance(hazelcastConfig);
Pavlin Radoslavovda7ef612013-10-30 16:12:14 -0700159
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700160 restApi.addRestletRoutable(new DatagridWebRoutable());
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700161 }
162
163 /**
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800164 * Create an event channel.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700165 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800166 * If the channel already exists, just return it.
167 * NOTE: The channel is started automatically.
168 *
169 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700170 * @param <K> the type of the Key in the Key-Value store.
171 * @param <V> the type of the Value in the Key-Value store.
172 * @param typeK the type of the Key in the Key-Value store.
173 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800174 * @return the event channel for the channel name.
175 */
176 @Override
177 public <K, V> IEventChannel<K, V> createChannel(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700178 Class<K> typeK, Class<V> typeV) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700179 synchronized (eventChannels) {
180 IEventChannel<K, V> eventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700181 createChannelImpl(channelName, typeK, typeV);
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700182 eventChannel.startup();
183 return eventChannel;
Ray Milkey9c8a2132014-04-02 15:16:42 -0700184 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800185 }
186
187 /**
188 * Create an event channel implementation.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700189 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800190 * If the channel already exists, just return it.
191 * NOTE: The caller must call IEventChannel.startup() to startup the
192 * channel operation.
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700193 * NOTE: The caller must own the lock on "eventChannels".
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800194 *
195 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700196 * @param <K> the type of the Key in the Key-Value store.
197 * @param <V> the type of the Value in the Key-Value store.
198 * @param typeK the type of the Key in the Key-Value store.
199 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800200 * @return the event channel for the channel name.
201 */
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700202 private <K, V> IEventChannel<K, V> createChannelImpl(
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700203 String channelName,
204 Class<K> typeK, Class<V> typeV) {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700205 IEventChannel<?, ?> genericEventChannel =
206 eventChannels.get(channelName);
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800207
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700208 // Add the channel if the first listener
209 if (genericEventChannel == null) {
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700210 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700211 new HazelcastEventChannel<K, V>(hazelcastInstance,
212 channelName, typeK, typeV);
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700213 eventChannels.put(channelName, castedEventChannel);
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700214 return castedEventChannel;
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700215 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800216
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700217 //
218 // TODO: Find if we can use Java internal support to check for
219 // type mismatch.
220 //
221 if (!genericEventChannel.verifyKeyValueTypes(typeK, typeV)) {
222 throw new ClassCastException("Key-value type mismatch for event channel " + channelName);
223 }
224 @SuppressWarnings("unchecked")
225 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700226 (IEventChannel<K, V>) genericEventChannel;
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700227 return castedEventChannel;
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800228 }
229
230 /**
231 * Add event channel listener.
Ray Milkey9c8a2132014-04-02 15:16:42 -0700232 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800233 * NOTE: The channel is started automatically right after the listener
234 * is added.
235 *
236 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700237 * @param listener the listener to add.
238 * @param <K> the type of the Key in the Key-Value store.
239 * @param <V> the type of the Value in the Key-Value store.
240 * @param typeK the type of the Key in the Key-Value store.
241 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800242 * @return the event channel for the channel name.
243 */
244 @Override
245 public <K, V> IEventChannel<K, V> addListener(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700246 IEventChannelListener<K, V> listener,
247 Class<K> typeK, Class<V> typeV) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700248 synchronized (eventChannels) {
249 IEventChannel<K, V> eventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700250 createChannelImpl(channelName, typeK, typeV);
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700251 eventChannel.addListener(listener);
252 eventChannel.startup();
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800253
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700254 return eventChannel;
Ray Milkey9c8a2132014-04-02 15:16:42 -0700255 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800256 }
257
258 /**
259 * Remove event channel listener.
260 *
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700261 * @param <K> the type of the Key in the Key-Value store.
262 * @param <V> the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800263 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700264 * @param listener the listener to remove.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800265 */
266 @Override
267 public <K, V> void removeListener(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700268 IEventChannelListener<K, V> listener) {
Ray Milkey9c8a2132014-04-02 15:16:42 -0700269 synchronized (eventChannels) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700270 IEventChannel<?, ?> genericEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700271 eventChannels.get(channelName);
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800272
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700273 if (genericEventChannel != null) {
274 //
275 // TODO: Find if we can use Java internal support to check for
276 // type mismatch.
277 // NOTE: Using "ClassCastException" exception below doesn't
278 // work.
279 //
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700280 @SuppressWarnings("unchecked")
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700281 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700282 (IEventChannel<K, V>) genericEventChannel;
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700283 castedEventChannel.removeListener(listener);
284 }
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700285 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800286 }
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700287}