blob: 5758b3861234389675bf0d436397c713ef9a95a5 [file] [log] [blame]
Jonathan Hart6df90172014-04-03 10:13:11 -07001package net.onrc.onos.core.datagrid;
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -07002
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;
Jonathan Hart6df90172014-04-03 10:13:11 -070015import net.onrc.onos.core.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";
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070036 private static final String HAZELCAST_DEFAULT_XML = "conf/hazelcast.default.xml";
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070037 private HazelcastInstance hazelcastInstance;
38 private Config hazelcastConfig;
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070039
Pavlin Radoslavov07af5f22014-03-21 15:17:58 -070040 //
41 // NOTE: eventChannels is kept thread safe by using explicit "synchronized"
42 // blocks below. Those are needed to protect the integrity of each entry
43 // instance, and avoid preemption during channel creation/startup.
44 //
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070045 private final Map<String, IEventChannel<?, ?>> eventChannels = new HashMap<>();
Pavlin Radoslavov7940b652014-02-13 19:42:05 -080046
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -070047 /**
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070048 * Load the Hazelcast Datagrid configuration file.
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070049 *
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070050 * @param configFilename the configuration filename.
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070051 */
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070052 public void loadHazelcastConfig(String configFilename) {
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070053 /*
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070054 System.setProperty("hazelcast.socket.receive.buffer.size", "32");
55 System.setProperty("hazelcast.socket.send.buffer.size", "32");
56 */
57 // System.setProperty("hazelcast.heartbeat.interval.seconds", "100");
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080058
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070059 // Init from configuration file
60 try {
61 hazelcastConfig = new FileSystemXmlConfig(configFilename);
62 } catch (FileNotFoundException e) {
63 log.error("Error opening Hazelcast XML configuration. File not found: " + configFilename, e);
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070064
65 // Fallback mechanism to support running unit test without setup.
66 log.error("Falling back to default Hazelcast XML {}", HAZELCAST_DEFAULT_XML);
67 try {
68 hazelcastConfig = new FileSystemXmlConfig(HAZELCAST_DEFAULT_XML);
69 } catch (FileNotFoundException e2) {
70 log.error("Error opening fall back Hazelcast XML configuration. "
71 + "File not found: " + HAZELCAST_DEFAULT_XML, e2);
72 // XXX probably should throw some exception to kill ONOS instead.
73 }
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070074 }
75 /*
76 hazelcastConfig.setProperty(GroupProperties.PROP_IO_THREAD_COUNT, "1");
77 hazelcastConfig.setProperty(GroupProperties.PROP_OPERATION_THREAD_COUNT, "1");
78 hazelcastConfig.setProperty(GroupProperties.PROP_EVENT_THREAD_COUNT, "1");
79 */
80 //
81 hazelcastConfig.setProperty(GroupProperties.PROP_EVENT_QUEUE_CAPACITY, "4000000");
82 hazelcastConfig.setProperty(GroupProperties.PROP_SOCKET_RECEIVE_BUFFER_SIZE, "4096");
83 hazelcastConfig.setProperty(GroupProperties.PROP_SOCKET_SEND_BUFFER_SIZE, "4096");
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070084 }
85
86 /**
87 * Shutdown the Hazelcast Datagrid operation.
88 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080089 @Override
90 protected void finalize() {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070091 close();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070092 }
93
94 /**
95 * Shutdown the Hazelcast Datagrid operation.
96 */
97 public void close() {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070098 Hazelcast.shutdownAll();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070099 }
100
101 /**
102 * Get the collection of offered module services.
103 *
104 * @return the collection of offered module services.
105 */
106 @Override
107 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800108 Collection<Class<? extends IFloodlightService>> l =
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700109 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700110 l.add(IDatagridService.class);
111 return l;
112 }
113
114 /**
115 * Get the collection of implemented services.
116 *
117 * @return the collection of implemented services.
118 */
119 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800120 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700121 getServiceImpls() {
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700122 Map<Class<? extends IFloodlightService>,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700123 IFloodlightService> m =
124 new HashMap<Class<? extends IFloodlightService>,
125 IFloodlightService>();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700126 m.put(IDatagridService.class, this);
127 return m;
128 }
129
130 /**
131 * Get the collection of modules this module depends on.
132 *
133 * @return the collection of modules this module depends on.
134 */
135 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800136 public Collection<Class<? extends IFloodlightService>>
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700137 getModuleDependencies() {
138 Collection<Class<? extends IFloodlightService>> l =
139 new ArrayList<Class<? extends IFloodlightService>>();
140 l.add(IFloodlightProviderService.class);
141 l.add(IRestApiService.class);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700142 return l;
143 }
144
145 /**
146 * Initialize the module.
147 *
148 * @param context the module context to use for the initialization.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700149 * @throws FloodlightModuleException on error
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700150 */
151 @Override
152 public void init(FloodlightModuleContext context)
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700153 throws FloodlightModuleException {
154 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700155
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700156 // Get the configuration file name and configure the Datagrid
157 Map<String, String> configMap = context.getConfigParams(this);
158 String configFilename = configMap.get(HAZELCAST_CONFIG_FILE);
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -0700159 this.loadHazelcastConfig(configFilename);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700160 }
161
162 /**
163 * Startup module operation.
164 *
165 * @param context the module context to use for the startup.
166 */
167 @Override
168 public void startUp(FloodlightModuleContext context) {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700169 hazelcastInstance = Hazelcast.newHazelcastInstance(hazelcastConfig);
Pavlin Radoslavovda7ef612013-10-30 16:12:14 -0700170
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700171 restApi.addRestletRoutable(new DatagridWebRoutable());
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700172 }
173
174 /**
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800175 * Create an event channel.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700176 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800177 * If the channel already exists, just return it.
178 * NOTE: The channel is started automatically.
179 *
180 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700181 * @param <K> the type of the Key in the Key-Value store.
182 * @param <V> the type of the Value in the Key-Value store.
183 * @param typeK the type of the Key in the Key-Value store.
184 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800185 * @return the event channel for the channel name.
186 */
187 @Override
188 public <K, V> IEventChannel<K, V> createChannel(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700189 Class<K> typeK, Class<V> typeV) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700190 synchronized (eventChannels) {
191 IEventChannel<K, V> eventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700192 createChannelImpl(channelName, typeK, typeV);
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700193 eventChannel.startup();
194 return eventChannel;
Ray Milkey9c8a2132014-04-02 15:16:42 -0700195 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800196 }
197
198 /**
199 * Create an event channel implementation.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700200 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800201 * If the channel already exists, just return it.
202 * NOTE: The caller must call IEventChannel.startup() to startup the
203 * channel operation.
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700204 * NOTE: The caller must own the lock on "eventChannels".
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800205 *
206 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700207 * @param <K> the type of the Key in the Key-Value store.
208 * @param <V> the type of the Value in the Key-Value store.
209 * @param typeK the type of the Key in the Key-Value store.
210 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800211 * @return the event channel for the channel name.
212 */
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700213 private <K, V> IEventChannel<K, V> createChannelImpl(
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700214 String channelName,
215 Class<K> typeK, Class<V> typeV) {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700216 IEventChannel<?, ?> genericEventChannel =
217 eventChannels.get(channelName);
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800218
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700219 // Add the channel if the first listener
220 if (genericEventChannel == null) {
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700221 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700222 new HazelcastEventChannel<K, V>(hazelcastInstance,
223 channelName, typeK, typeV);
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700224 eventChannels.put(channelName, castedEventChannel);
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700225 return castedEventChannel;
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700226 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800227
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700228 //
229 // TODO: Find if we can use Java internal support to check for
230 // type mismatch.
231 //
232 if (!genericEventChannel.verifyKeyValueTypes(typeK, typeV)) {
233 throw new ClassCastException("Key-value type mismatch for event channel " + channelName);
234 }
235 @SuppressWarnings("unchecked")
236 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700237 (IEventChannel<K, V>) genericEventChannel;
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700238 return castedEventChannel;
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800239 }
240
241 /**
242 * Add event channel listener.
Ray Milkey9c8a2132014-04-02 15:16:42 -0700243 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800244 * NOTE: The channel is started automatically right after the listener
245 * is added.
246 *
247 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700248 * @param listener the listener to add.
249 * @param <K> the type of the Key in the Key-Value store.
250 * @param <V> the type of the Value in the Key-Value store.
251 * @param typeK the type of the Key in the Key-Value store.
252 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800253 * @return the event channel for the channel name.
254 */
255 @Override
256 public <K, V> IEventChannel<K, V> addListener(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700257 IEventChannelListener<K, V> listener,
258 Class<K> typeK, Class<V> typeV) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700259 synchronized (eventChannels) {
260 IEventChannel<K, V> eventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700261 createChannelImpl(channelName, typeK, typeV);
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700262 eventChannel.addListener(listener);
263 eventChannel.startup();
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800264
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700265 return eventChannel;
Ray Milkey9c8a2132014-04-02 15:16:42 -0700266 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800267 }
268
269 /**
270 * Remove event channel listener.
271 *
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700272 * @param <K> the type of the Key in the Key-Value store.
273 * @param <V> the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800274 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700275 * @param listener the listener to remove.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800276 */
277 @Override
278 public <K, V> void removeListener(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700279 IEventChannelListener<K, V> listener) {
Ray Milkey9c8a2132014-04-02 15:16:42 -0700280 synchronized (eventChannels) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700281 IEventChannel<?, ?> genericEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700282 eventChannels.get(channelName);
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800283
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700284 if (genericEventChannel != null) {
285 //
286 // TODO: Find if we can use Java internal support to check for
287 // type mismatch.
288 // NOTE: Using "ClassCastException" exception below doesn't
289 // work.
290 //
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700291 @SuppressWarnings("unchecked")
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700292 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700293 (IEventChannel<K, V>) genericEventChannel;
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700294 castedEventChannel.removeListener(listener);
295 }
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700296 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800297 }
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700298}