blob: 855d6a42e887f36fbaf74a6531ee3f3d6d3271c1 [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 Radoslavov1eee2c82013-10-15 02:30:32 -070016import org.slf4j.Logger;
17import org.slf4j.LoggerFactory;
18
19import com.hazelcast.config.Config;
20import com.hazelcast.config.FileSystemXmlConfig;
21import com.hazelcast.core.Hazelcast;
22import com.hazelcast.core.HazelcastInstance;
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070023
24/**
25 * A datagrid service that uses Hazelcast as a datagrid.
26 * The relevant data is stored in the Hazelcast datagrid and shared as
27 * appropriate in a multi-node cluster.
28 */
29public class HazelcastDatagrid implements IFloodlightModule, IDatagridService {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070030 static final Logger log = LoggerFactory.getLogger(HazelcastDatagrid.class);
Yuta HIGUCHI6dfba392014-05-28 15:45:44 -070031
32 /**
33 * The name of Hazelcast instance in this JVM.
34 */
35 public static final String ONOS_HAZELCAST_INSTANCE = "ONOS_HazelcastInstance";
36
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070037 private IRestApiService restApi;
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070038
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070039 static final String HAZELCAST_CONFIG_FILE = "datagridConfig";
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070040 private static final String HAZELCAST_DEFAULT_XML = "conf/hazelcast.default.xml";
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070041 private HazelcastInstance hazelcastInstance;
42 private Config hazelcastConfig;
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070043
Pavlin Radoslavov07af5f22014-03-21 15:17:58 -070044 //
45 // NOTE: eventChannels is kept thread safe by using explicit "synchronized"
46 // blocks below. Those are needed to protect the integrity of each entry
47 // instance, and avoid preemption during channel creation/startup.
48 //
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070049 private final Map<String, IEventChannel<?, ?>> eventChannels = new HashMap<>();
Pavlin Radoslavov7940b652014-02-13 19:42:05 -080050
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -070051 /**
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070052 * Load the Hazelcast Datagrid configuration file.
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070053 *
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070054 * @param configFilename the configuration filename.
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070055 */
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070056 public void loadHazelcastConfig(String configFilename) {
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070057 /*
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070058 System.setProperty("hazelcast.socket.receive.buffer.size", "32");
59 System.setProperty("hazelcast.socket.send.buffer.size", "32");
60 */
61 // System.setProperty("hazelcast.heartbeat.interval.seconds", "100");
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080062
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070063 // Init from configuration file
64 try {
65 hazelcastConfig = new FileSystemXmlConfig(configFilename);
66 } catch (FileNotFoundException e) {
67 log.error("Error opening Hazelcast XML configuration. File not found: " + configFilename, e);
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -070068
69 // Fallback mechanism to support running unit test without setup.
70 log.error("Falling back to default Hazelcast XML {}", HAZELCAST_DEFAULT_XML);
71 try {
72 hazelcastConfig = new FileSystemXmlConfig(HAZELCAST_DEFAULT_XML);
73 } catch (FileNotFoundException e2) {
74 log.error("Error opening fall back Hazelcast XML configuration. "
75 + "File not found: " + HAZELCAST_DEFAULT_XML, e2);
76 // XXX probably should throw some exception to kill ONOS instead.
77 }
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070078 }
Yuta HIGUCHI6dfba392014-05-28 15:45:44 -070079
80 // set the name of Hazelcast instance in this JVM.
81 hazelcastConfig.setInstanceName(ONOS_HAZELCAST_INSTANCE);
82
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070083 /*
84 hazelcastConfig.setProperty(GroupProperties.PROP_IO_THREAD_COUNT, "1");
85 hazelcastConfig.setProperty(GroupProperties.PROP_OPERATION_THREAD_COUNT, "1");
86 hazelcastConfig.setProperty(GroupProperties.PROP_EVENT_THREAD_COUNT, "1");
87 */
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070088 }
89
90 /**
91 * Shutdown the Hazelcast Datagrid operation.
92 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080093 @Override
94 protected void finalize() {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -070095 close();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -070096 }
97
98 /**
99 * Shutdown the Hazelcast Datagrid operation.
100 */
101 public void close() {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700102 Hazelcast.shutdownAll();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700103 }
104
105 /**
106 * Get the collection of offered module services.
107 *
108 * @return the collection of offered module services.
109 */
110 @Override
111 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800112 Collection<Class<? extends IFloodlightService>> l =
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700113 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700114 l.add(IDatagridService.class);
115 return l;
116 }
117
118 /**
119 * Get the collection of implemented services.
120 *
121 * @return the collection of implemented services.
122 */
123 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800124 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700125 getServiceImpls() {
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700126 Map<Class<? extends IFloodlightService>,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700127 IFloodlightService> m =
128 new HashMap<Class<? extends IFloodlightService>,
129 IFloodlightService>();
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700130 m.put(IDatagridService.class, this);
131 return m;
132 }
133
134 /**
135 * Get the collection of modules this module depends on.
136 *
137 * @return the collection of modules this module depends on.
138 */
139 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800140 public Collection<Class<? extends IFloodlightService>>
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700141 getModuleDependencies() {
142 Collection<Class<? extends IFloodlightService>> l =
143 new ArrayList<Class<? extends IFloodlightService>>();
144 l.add(IFloodlightProviderService.class);
145 l.add(IRestApiService.class);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700146 return l;
147 }
148
149 /**
150 * Initialize the module.
151 *
152 * @param context the module context to use for the initialization.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700153 * @throws FloodlightModuleException on error
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700154 */
155 @Override
156 public void init(FloodlightModuleContext context)
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700157 throws FloodlightModuleException {
158 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700159
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700160 // Get the configuration file name and configure the Datagrid
161 Map<String, String> configMap = context.getConfigParams(this);
162 String configFilename = configMap.get(HAZELCAST_CONFIG_FILE);
Yuta HIGUCHI3ebc9482014-05-08 16:28:28 -0700163 this.loadHazelcastConfig(configFilename);
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700164 }
165
166 /**
167 * Startup module operation.
168 *
169 * @param context the module context to use for the startup.
170 */
171 @Override
172 public void startUp(FloodlightModuleContext context) {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700173 hazelcastInstance = Hazelcast.newHazelcastInstance(hazelcastConfig);
Pavlin Radoslavovda7ef612013-10-30 16:12:14 -0700174
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700175 restApi.addRestletRoutable(new DatagridWebRoutable());
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700176 }
177
178 /**
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800179 * Create an event channel.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700180 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800181 * If the channel already exists, just return it.
182 * NOTE: The channel is started automatically.
183 *
184 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700185 * @param <K> the type of the Key in the Key-Value store.
186 * @param <V> the type of the Value in the Key-Value store.
187 * @param typeK the type of the Key in the Key-Value store.
188 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800189 * @return the event channel for the channel name.
190 */
191 @Override
192 public <K, V> IEventChannel<K, V> createChannel(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700193 Class<K> typeK, Class<V> typeV) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700194 synchronized (eventChannels) {
195 IEventChannel<K, V> eventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700196 createChannelImpl(channelName, typeK, typeV);
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700197 eventChannel.startup();
198 return eventChannel;
Ray Milkey9c8a2132014-04-02 15:16:42 -0700199 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800200 }
201
202 /**
203 * Create an event channel implementation.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700204 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800205 * If the channel already exists, just return it.
206 * NOTE: The caller must call IEventChannel.startup() to startup the
207 * channel operation.
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700208 * NOTE: The caller must own the lock on "eventChannels".
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800209 *
210 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700211 * @param <K> the type of the Key in the Key-Value store.
212 * @param <V> the type of the Value in the Key-Value store.
213 * @param typeK the type of the Key in the Key-Value store.
214 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800215 * @return the event channel for the channel name.
216 */
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700217 private <K, V> IEventChannel<K, V> createChannelImpl(
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700218 String channelName,
219 Class<K> typeK, Class<V> typeV) {
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700220 IEventChannel<?, ?> genericEventChannel =
221 eventChannels.get(channelName);
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800222
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700223 // Add the channel if the first listener
224 if (genericEventChannel == null) {
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700225 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700226 new HazelcastEventChannel<K, V>(hazelcastInstance,
227 channelName, typeK, typeV);
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700228 eventChannels.put(channelName, castedEventChannel);
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700229 return castedEventChannel;
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700230 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800231
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700232 //
233 // TODO: Find if we can use Java internal support to check for
234 // type mismatch.
235 //
236 if (!genericEventChannel.verifyKeyValueTypes(typeK, typeV)) {
237 throw new ClassCastException("Key-value type mismatch for event channel " + channelName);
238 }
239 @SuppressWarnings("unchecked")
240 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700241 (IEventChannel<K, V>) genericEventChannel;
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700242 return castedEventChannel;
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800243 }
244
245 /**
246 * Add event channel listener.
Ray Milkey9c8a2132014-04-02 15:16:42 -0700247 * <p/>
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800248 * NOTE: The channel is started automatically right after the listener
249 * is added.
250 *
251 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700252 * @param listener the listener to add.
253 * @param <K> the type of the Key in the Key-Value store.
254 * @param <V> the type of the Value in the Key-Value store.
255 * @param typeK the type of the Key in the Key-Value store.
256 * @param typeV the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800257 * @return the event channel for the channel name.
258 */
259 @Override
260 public <K, V> IEventChannel<K, V> addListener(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700261 IEventChannelListener<K, V> listener,
262 Class<K> typeK, Class<V> typeV) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700263 synchronized (eventChannels) {
264 IEventChannel<K, V> eventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700265 createChannelImpl(channelName, typeK, typeV);
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700266 eventChannel.addListener(listener);
267 eventChannel.startup();
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800268
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700269 return eventChannel;
Ray Milkey9c8a2132014-04-02 15:16:42 -0700270 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800271 }
272
273 /**
274 * Remove event channel listener.
275 *
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700276 * @param <K> the type of the Key in the Key-Value store.
277 * @param <V> the type of the Value in the Key-Value store.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800278 * @param channelName the event channel name.
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700279 * @param listener the listener to remove.
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800280 */
281 @Override
282 public <K, V> void removeListener(String channelName,
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700283 IEventChannelListener<K, V> listener) {
Ray Milkey9c8a2132014-04-02 15:16:42 -0700284 synchronized (eventChannels) {
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700285 IEventChannel<?, ?> genericEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700286 eventChannels.get(channelName);
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800287
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700288 if (genericEventChannel != null) {
289 //
290 // TODO: Find if we can use Java internal support to check for
291 // type mismatch.
292 // NOTE: Using "ClassCastException" exception below doesn't
293 // work.
294 //
Pavlin Radoslavove561a4c2014-04-01 14:10:55 -0700295 @SuppressWarnings("unchecked")
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700296 IEventChannel<K, V> castedEventChannel =
Ray Milkey9c8a2132014-04-02 15:16:42 -0700297 (IEventChannel<K, V>) genericEventChannel;
Pavlin Radoslavov00fad592014-03-21 11:32:34 -0700298 castedEventChannel.removeListener(listener);
299 }
Ray Milkey0ab2d8a2014-03-20 14:30:10 -0700300 }
Pavlin Radoslavov7940b652014-02-13 19:42:05 -0800301 }
Pavlin Radoslavov1eee2c82013-10-15 02:30:32 -0700302}