MD-SAL Statistics Manager: Added support for queue statistics collection
[controller.git] / opendaylight / md-sal / zeromq-routingtable / implementation / src / main / java / org / opendaylight / controller / sal / connector / remoterpc / impl / RoutingTableImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.sal.connector.remoterpc.impl;
10
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;
25
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;
33 import java.util.Set;
34 import java.util.concurrent.ConcurrentMap;
35
36 /**
37  * @author: syedbahm
38  */
39 public class RoutingTableImpl<I, R> implements RoutingTable<I, R>, ICacheUpdateAware<I, R> {
40     public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache";
41
42     private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class);
43
44     private IClusterGlobalServices clusterGlobalServices = null;
45     private RoutingTableImpl routingTableInstance = null;
46     private ConcurrentMap routingTableCache = null;
47     private Set<RouteChangeListener> routeChangeListeners = Collections
48             .synchronizedSet(new HashSet<RouteChangeListener>());
49
50     public RoutingTableImpl() {
51     }
52
53     @Override
54     public void addRoute(I routeId, R route) throws RoutingTableException {
55         throw new UnsupportedOperationException(" Not implemented yet!");
56     }
57
58     @Override
59     public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
60         Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
61         Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
62         try {
63
64             Set<R> existingRoute = null;
65             // ok does the global route is already registered ?
66             if ((existingRoute = getRoutes(routeId)) == null) {
67
68                 if (log.isDebugEnabled()) {
69                     log.debug("addGlobalRoute: adding  a new route with id" + routeId + " and value = "
70                             + route);
71                 }
72                 // lets start a transaction
73                 clusterGlobalServices.tbegin();
74                 Set<R> routes = new HashSet<R>();
75                 routes.add(route);
76                 routingTableCache.put(routeId, routes);
77                 clusterGlobalServices.tcommit();
78             } else {
79                 throw new DuplicateRouteException(" There is already existing route " + existingRoute);
80             }
81
82         } catch (NotSupportedException e) {
83             throw new RoutingTableException("Transaction error - while trying to create route id="
84                     + routeId + "with route" + route, e);
85         } catch (HeuristicRollbackException e) {
86             throw new RoutingTableException("Transaction error - while trying to create route id="
87                     + routeId + "with route" + route, e);
88         } catch (RollbackException e) {
89             throw new RoutingTableException("Transaction error - while trying to create route id="
90                     + routeId + "with route" + route, e);
91         } catch (HeuristicMixedException e) {
92             throw new RoutingTableException("Transaction error - while trying to create route id="
93                     + routeId + "with route" + route, e);
94         } catch (javax.transaction.SystemException e) {
95             throw new SystemException("System error occurred - while trying to create with value", e);
96         }
97
98     }
99
100     @Override
101     public void removeRoute(I routeId, R route) {
102         throw new UnsupportedOperationException("Not implemented yet!");
103     }
104
105     @Override
106     public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException {
107         Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
108         try {
109             if (log.isDebugEnabled()) {
110                 log.debug("removeGlobalRoute: removing  a new route with id" + routeId);
111             }
112             // lets start a transaction
113             clusterGlobalServices.tbegin();
114
115             routingTableCache.remove(routeId);
116             clusterGlobalServices.tcommit();
117
118         } catch (NotSupportedException e) {
119             throw new RoutingTableException("Transaction error - while trying to remove route id="
120                     + routeId, e);
121         } catch (HeuristicRollbackException e) {
122             throw new RoutingTableException("Transaction error - while trying to remove route id="
123                     + routeId, e);
124         } catch (RollbackException e) {
125             throw new RoutingTableException("Transaction error - while trying to remove route id="
126                     + routeId, e);
127         } catch (HeuristicMixedException e) {
128             throw new RoutingTableException("Transaction error - while trying to remove route id="
129                     + routeId, e);
130         } catch (javax.transaction.SystemException e) {
131             throw new SystemException("System error occurred - while trying to remove with value", e);
132         }
133     }
134
135     @Override
136     public Set<R> getRoutes(I routeId) {
137
138         // Note: currently works for global routes only wherein there is just single
139         // route
140         Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!");
141         return (Set<R>) routingTableCache.get(routeId);
142     }
143
144     @Override
145     public R getARoute(I routeId) {
146         throw new UnsupportedOperationException("Not implemented yet!");
147     }
148
149     /**
150      * @deprecated doesn't do anything will be removed once listeners used
151      *             whiteboard pattern Registers listener for sending any change
152      *             notification
153      * @param listener
154      */
155     @Override
156     public void registerRouteChangeListener(RouteChangeListener listener) {
157
158     }
159
160     public void setRouteChangeListener(RouteChangeListener rcl) {
161         if(rcl != null){
162             routeChangeListeners.add(rcl);
163         }else{
164             log.warn("setRouteChangeListener called with null listener");
165         }
166     }
167
168     public void unSetRouteChangeListener(RouteChangeListener rcl) {
169         if(rcl != null){
170          routeChangeListeners.remove(rcl);
171         }else{
172             log.warn("unSetRouteChangeListener called with null listener");
173         }
174     }
175
176     /**
177      * Returning the set of route change listeners for Unit testing Note: the
178      * package scope is default
179      *
180      * @return List of registered RouteChangeListener<I,R> listeners
181      */
182     Set<RouteChangeListener> getRegisteredRouteChangeListeners() {
183         return routeChangeListeners;
184     }
185
186     public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
187         this.clusterGlobalServices = clusterGlobalServices;
188     }
189
190     public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
191         if((clusterGlobalServices != null ) &&  (this.clusterGlobalServices.equals(clusterGlobalServices))){
192             this.clusterGlobalServices = null;
193         }
194     }
195
196     /**
197      * Creates the Routing Table clustered global services cache
198      *
199      * @throws CacheExistException
200      *           -- cluster global services exception when cache exist
201      * @throws CacheConfigException
202      *           -- cluster global services exception during cache config
203      * @throws CacheListenerAddException
204      *           -- cluster global services exception during adding of listener
205      */
206
207     void createRoutingTableCache() throws CacheExistException, CacheConfigException,
208             CacheListenerAddException {
209         // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
210         // should be caching?
211
212         // let us check here if the cache already exists -- if so don't create
213         if (!clusterGlobalServices.existCache(ROUTING_TABLE_GLOBAL_CACHE)) {
214
215             if (log.isDebugEnabled()) {
216                 log.debug("createRoutingTableCache: creating a new routing table cache "
217                         + ROUTING_TABLE_GLOBAL_CACHE);
218             }
219             routingTableCache = clusterGlobalServices.createCache(ROUTING_TABLE_GLOBAL_CACHE,
220                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
221         } else {
222             if (log.isDebugEnabled()) {
223                 log.debug("createRoutingTableCache: found existing routing table cache "
224                         + ROUTING_TABLE_GLOBAL_CACHE);
225             }
226             routingTableCache = clusterGlobalServices.getCache(ROUTING_TABLE_GLOBAL_CACHE);
227         }
228
229     }
230
231     /**
232      * Function called by the dependency manager when all the required
233      * dependencies are satisfied
234      *
235      */
236     void init(Component c) {
237         try {
238
239             createRoutingTableCache();
240         } catch (CacheExistException e) {
241             throw new IllegalStateException("could not construct routing table cache");
242         } catch (CacheConfigException e) {
243             throw new IllegalStateException("could not construct routing table cache");
244         } catch (CacheListenerAddException e) {
245             throw new IllegalStateException("could not construct routing table cache");
246         }
247     }
248
249     /**
250      * Get routing table method is useful for unit testing <note>It has package
251      * scope</note>
252      */
253     ConcurrentMap getRoutingTableCache() {
254         return this.routingTableCache;
255     }
256
257     /**
258      * Invoked when a new entry is available in the cache, the key is only
259      * provided, the value will come as an entryUpdate invocation
260      *
261      * @param key
262      *          Key for the entry just created
263      * @param cacheName
264      *          name of the cache for which update has been received
265      * @param originLocal
266      *          true if the event is generated from this node
267      */
268     @Override
269     public void entryCreated(I key, String cacheName, boolean originLocal) {
270         // TBD: do we require this.
271         if (log.isDebugEnabled()) {
272             log.debug("RoutingTableUpdates: entryCreated  routeId = " + key + " cacheName=" + cacheName);
273         }
274     }
275
276     /**
277      * Called anytime a given entry is updated
278      *
279      * @param key
280      *          Key for the entry modified
281      * @param new_value
282      *          the new value the key will have
283      * @param cacheName
284      *          name of the cache for which update has been received
285      * @param originLocal
286      *          true if the event is generated from this node
287      */
288     @Override
289     public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
290         if (log.isDebugEnabled()) {
291             log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + ",value = " + new_value
292                     + " ,cacheName=" + cacheName + " originLocal="+originLocal);
293         }
294         if (!originLocal) {
295             for (RouteChangeListener rcl : routeChangeListeners) {
296                 rcl.onRouteUpdated(key, new_value);
297             }
298         }
299     }
300
301     /**
302      * Called anytime a given key is removed from the ConcurrentHashMap we are
303      * listening to.
304      *
305      * @param key
306      *          Key of the entry removed
307      * @param cacheName
308      *          name of the cache for which update has been received
309      * @param originLocal
310      *          true if the event is generated from this node
311      */
312     @Override
313     public void entryDeleted(I key, String cacheName, boolean originLocal) {
314         if (log.isDebugEnabled()) {
315             log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + " local = " + originLocal
316                     + " cacheName=" + cacheName + " originLocal="+originLocal);
317         }
318         if (!originLocal) {
319             for (RouteChangeListener rcl : routeChangeListeners) {
320                 rcl.onRouteDeleted(key);
321             }
322         }
323     }
324 }