2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.sal.connector.remoterpc.impl;
11 import com.google.common.base.Preconditions;
12 import org.apache.felix.dm.Component;
13 import org.opendaylight.controller.clustering.services.CacheConfigException;
14 import org.opendaylight.controller.clustering.services.CacheExistException;
15 import org.opendaylight.controller.clustering.services.CacheListenerAddException;
16 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
17 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
18 import org.opendaylight.controller.clustering.services.IClusterServices;
19 import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
20 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
21 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
22 import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
26 import javax.transaction.HeuristicMixedException;
27 import javax.transaction.HeuristicRollbackException;
28 import javax.transaction.NotSupportedException;
29 import javax.transaction.RollbackException;
30 import java.util.Collections;
31 import java.util.EnumSet;
32 import java.util.HashSet;
35 import java.util.concurrent.ConcurrentMap;
40 public class RoutingTableImpl<I, R> implements RoutingTable<I, R>, ICacheUpdateAware<I, R> {
41 public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache";
43 private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class);
45 private IClusterGlobalServices clusterGlobalServices = null;
46 private RoutingTableImpl routingTableInstance = null;
47 private ConcurrentMap routingTableCache = null;
48 private Set<RouteChangeListener> routeChangeListeners = Collections
49 .synchronizedSet(new HashSet<RouteChangeListener>());
51 public RoutingTableImpl() {
55 public void addRoute(I routeId, R route) throws RoutingTableException {
56 throw new UnsupportedOperationException(" Not implemented yet!");
60 public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
61 Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
62 Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
65 Set<R> existingRoute = null;
66 // ok does the global route is already registered ?
67 if ((existingRoute = getRoutes(routeId)) == null) {
69 if (log.isDebugEnabled()) {
70 log.debug("addGlobalRoute: adding a new route with id" + routeId + " and value = "
73 // lets start a transaction
74 clusterGlobalServices.tbegin();
75 Set<R> routes = new HashSet<R>();
77 routingTableCache.put(routeId, routes);
78 clusterGlobalServices.tcommit();
80 throw new DuplicateRouteException(" There is already existing route " + existingRoute);
83 } catch (NotSupportedException e) {
84 throw new RoutingTableException("Transaction error - while trying to create route id="
85 + routeId + "with route" + route, e);
86 } catch (HeuristicRollbackException e) {
87 throw new RoutingTableException("Transaction error - while trying to create route id="
88 + routeId + "with route" + route, e);
89 } catch (RollbackException e) {
90 throw new RoutingTableException("Transaction error - while trying to create route id="
91 + routeId + "with route" + route, e);
92 } catch (HeuristicMixedException e) {
93 throw new RoutingTableException("Transaction error - while trying to create route id="
94 + routeId + "with route" + route, e);
95 } catch (javax.transaction.SystemException e) {
96 throw new SystemException("System error occurred - while trying to create with value", e);
102 public void removeRoute(I routeId, R route) {
103 throw new UnsupportedOperationException("Not implemented yet!");
107 public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException {
108 Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
110 if (log.isDebugEnabled()) {
111 log.debug("removeGlobalRoute: removing a new route with id" + routeId);
113 // lets start a transaction
114 clusterGlobalServices.tbegin();
116 routingTableCache.remove(routeId);
117 clusterGlobalServices.tcommit();
119 } catch (NotSupportedException e) {
120 throw new RoutingTableException("Transaction error - while trying to remove route id="
122 } catch (HeuristicRollbackException e) {
123 throw new RoutingTableException("Transaction error - while trying to remove route id="
125 } catch (RollbackException e) {
126 throw new RoutingTableException("Transaction error - while trying to remove route id="
128 } catch (HeuristicMixedException e) {
129 throw new RoutingTableException("Transaction error - while trying to remove route id="
131 } catch (javax.transaction.SystemException e) {
132 throw new SystemException("System error occurred - while trying to remove with value", e);
137 public Set<R> getRoutes(I routeId) {
139 // Note: currently works for global routes only wherein there is just single
141 Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!");
142 return (Set<R>) routingTableCache.get(routeId);
146 public R getARoute(I routeId) {
147 throw new UnsupportedOperationException("Not implemented yet!");
151 * @deprecated doesn't do anything will be removed once listeners used
152 * whiteboard pattern Registers listener for sending any change
157 public void registerRouteChangeListener(RouteChangeListener listener) {
161 public void setRouteChangeListener(RouteChangeListener rcl) {
163 routeChangeListeners.add(rcl);
165 log.warn("setRouteChangeListener called with null listener");
169 public void unSetRouteChangeListener(RouteChangeListener rcl) {
171 routeChangeListeners.remove(rcl);
173 log.warn("unSetRouteChangeListener called with null listener");
178 * Returning the set of route change listeners for Unit testing Note: the
179 * package scope is default
181 * @return List of registered RouteChangeListener<I,R> listeners
183 Set<RouteChangeListener> getRegisteredRouteChangeListeners() {
184 return routeChangeListeners;
187 public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
188 this.clusterGlobalServices = clusterGlobalServices;
191 public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
192 if((clusterGlobalServices != null ) && (this.clusterGlobalServices.equals(clusterGlobalServices))){
193 this.clusterGlobalServices = null;
198 * Creates the Routing Table clustered global services cache
200 * @throws CacheExistException
201 * -- cluster global services exception when cache exist
202 * @throws CacheConfigException
203 * -- cluster global services exception during cache config
204 * @throws CacheListenerAddException
205 * -- cluster global services exception during adding of listener
208 void createRoutingTableCache() throws CacheExistException, CacheConfigException,
209 CacheListenerAddException {
210 // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
211 // should be caching?
213 // let us check here if the cache already exists -- if so don't create
214 if (!clusterGlobalServices.existCache(ROUTING_TABLE_GLOBAL_CACHE)) {
216 if (log.isDebugEnabled()) {
217 log.debug("createRoutingTableCache: creating a new routing table cache "
218 + ROUTING_TABLE_GLOBAL_CACHE);
220 routingTableCache = clusterGlobalServices.createCache(ROUTING_TABLE_GLOBAL_CACHE,
221 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
223 if (log.isDebugEnabled()) {
224 log.debug("createRoutingTableCache: found existing routing table cache "
225 + ROUTING_TABLE_GLOBAL_CACHE);
227 routingTableCache = clusterGlobalServices.getCache(ROUTING_TABLE_GLOBAL_CACHE);
233 * Function called by the dependency manager when all the required
234 * dependencies are satisfied
237 void init(Component c) {
240 createRoutingTableCache();
241 } catch (CacheExistException e) {
242 throw new IllegalStateException("could not construct routing table cache");
243 } catch (CacheConfigException e) {
244 throw new IllegalStateException("could not construct routing table cache");
245 } catch (CacheListenerAddException e) {
246 throw new IllegalStateException("could not construct routing table cache");
251 * Get routing table method is useful for unit testing <note>It has package
254 ConcurrentMap getRoutingTableCache() {
255 return this.routingTableCache;
259 * This is used from integration test NP rest API to check out the result of the
261 * <Note> For testing purpose only-- use it wisely</Note>
264 public String dumpRoutingTableCache(){
265 Set<Map.Entry<I, R>> cacheEntrySet = this.routingTableCache.entrySet();
266 StringBuilder sb = new StringBuilder();
267 for(Map.Entry<I,R> entry:cacheEntrySet){
268 sb.append("Key:").append(entry.getKey()).append("---->Value:")
269 .append((entry.getValue() != null)?entry.getValue():"null")
272 return sb.toString();
276 * Invoked when a new entry is available in the cache, the key is only
277 * provided, the value will come as an entryUpdate invocation
280 * Key for the entry just created
282 * name of the cache for which update has been received
284 * true if the event is generated from this node
287 public void entryCreated(I key, String cacheName, boolean originLocal) {
288 // TBD: do we require this.
289 if (log.isDebugEnabled()) {
290 log.debug("RoutingTableUpdates: entryCreated routeId = " + key + " cacheName=" + cacheName);
295 * Called anytime a given entry is updated
298 * Key for the entry modified
300 * the new value the key will have
302 * name of the cache for which update has been received
304 * true if the event is generated from this node
307 public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
308 if (log.isDebugEnabled()) {
309 log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + ",value = " + new_value
310 + " ,cacheName=" + cacheName + " originLocal="+originLocal);
313 for (RouteChangeListener rcl : routeChangeListeners) {
314 rcl.onRouteUpdated(key, new_value);
320 * Called anytime a given key is removed from the ConcurrentHashMap we are
324 * Key of the entry removed
326 * name of the cache for which update has been received
328 * true if the event is generated from this node
331 public void entryDeleted(I key, String cacheName, boolean originLocal) {
332 if (log.isDebugEnabled()) {
333 log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + " local = " + originLocal
334 + " cacheName=" + cacheName + " originLocal="+originLocal);
337 for (RouteChangeListener rcl : routeChangeListeners) {
338 rcl.onRouteDeleted(key);