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.*;
14 import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
15 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
16 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
17 import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
18 import org.osgi.framework.ServiceRegistration;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
22 import javax.transaction.HeuristicMixedException;
23 import javax.transaction.HeuristicRollbackException;
24 import javax.transaction.NotSupportedException;
25 import javax.transaction.RollbackException;
27 import java.util.concurrent.ConcurrentMap;
32 public class RoutingTableImpl<I, R> implements RoutingTable<I, R>,ICacheUpdateAware<I,R> {
33 public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache";
35 private Logger log = LoggerFactory
36 .getLogger(RoutingTableImpl.class);
38 private IClusterGlobalServices clusterGlobalServices = null;
39 private RoutingTableImpl routingTableInstance = null;
40 private ConcurrentMap routingTableCache = null;
41 private List<RouteChangeListener> routeChangeListeners = new ArrayList<RouteChangeListener>();
42 private ServiceRegistration cacheAwareRegistration = null;
44 public RoutingTableImpl() {
48 public void addRoute(I routeId, R route) throws RoutingTableException {
49 throw new UnsupportedOperationException(" Not implemented yet!");
53 public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
54 Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
55 Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
58 Set<R> existingRoute = null;
59 // ok does the global route is already registered ?
60 if ((existingRoute = getRoutes(routeId)) == null) {
62 if(log.isDebugEnabled()){
63 log.debug("addGlobalRoute: adding a new route with id"+ routeId + " and value = "+route);
65 // lets start a transaction
66 clusterGlobalServices.tbegin();
67 Set<R> routes = new HashSet<R>();
69 routingTableCache.put(routeId, routes);
70 clusterGlobalServices.tcommit();
72 throw new DuplicateRouteException(" There is already existing route " + existingRoute);
75 } catch (NotSupportedException e) {
76 throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
77 } catch (HeuristicRollbackException e) {
78 throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
79 } catch (RollbackException e) {
80 throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
81 } catch (HeuristicMixedException e) {
82 throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
83 } catch (javax.transaction.SystemException e){
84 throw new SystemException ( "System error occurred - while trying to create with value",e);
90 public void removeRoute(I routeId, R route) {
91 throw new UnsupportedOperationException("Not implemented yet!");
94 public void removeGlobalRoute(I routeId) {
95 routingTableCache.remove(routeId);
99 public Set<R> getRoutes(I routeId) {
101 //Note: currently works for global routes only wherein there is just single route
102 Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!");
103 return (Set<R>) routingTableCache.get(routeId);
107 public R getARoute(I routeId) {
108 throw new UnsupportedOperationException("Not implemented yet!");
112 * Registers listener for sending any change notification
117 public void registerRouteChangeListener(RouteChangeListener listener) {
118 routeChangeListeners.add(listener);
123 * Returning the list of route change listeners for Unit testing
124 * Note: the package scope is default
125 * @return List of registered RouteChangeListener<I,R> listeners
127 List<RouteChangeListener> getRegisteredRouteChangeListeners(){
128 return routeChangeListeners;
131 public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
132 this.clusterGlobalServices = clusterGlobalServices;
135 public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
136 if(cacheAwareRegistration != null) {
137 cacheAwareRegistration.unregister();
139 this.clusterGlobalServices = null;
143 * Creates the Routing Table clustered global services cache
144 * @throws CacheExistException -- cluster global services exception when cache exist
145 * @throws CacheConfigException -- cluster global services exception during cache config
146 * @throws CacheListenerAddException -- cluster global services exception during adding of listener
149 void createRoutingTableCache() throws CacheExistException, CacheConfigException, CacheListenerAddException {
150 // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
151 // should be caching?
153 // let us check here if the cache already exists -- if so don't create
154 if (!clusterGlobalServices.existCache(
155 ROUTING_TABLE_GLOBAL_CACHE)) {
157 if(log.isDebugEnabled()){
158 log.debug("createRoutingTableCache: creating a new routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
160 routingTableCache = clusterGlobalServices.createCache(
161 ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
163 if(log.isDebugEnabled()){
164 log.debug("createRoutingTableCache: found existing routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
166 routingTableCache = clusterGlobalServices.getCache(
167 ROUTING_TABLE_GLOBAL_CACHE);
173 * Function called by the dependency manager when all the required
174 * dependencies are satisfied
177 void init(Component c) {
180 createRoutingTableCache();
181 } catch (CacheExistException e) {
182 throw new IllegalStateException("could not construct routing table cache");
183 } catch (CacheConfigException e) {
184 throw new IllegalStateException("could not construct routing table cache");
185 } catch (CacheListenerAddException e) {
186 throw new IllegalStateException("could not construct routing table cache");
192 * Get routing table method is useful for unit testing
193 * <note>It has package scope</note>
195 ConcurrentMap getRoutingTableCache(){
196 return this.routingTableCache;
201 * Invoked when a new entry is available in the cache, the key is
202 * only provided, the value will come as an entryUpdate invocation
204 * @param key Key for the entry just created
205 * @param cacheName name of the cache for which update has been
207 * @param originLocal true if the event is generated from this
211 public void entryCreated(I key, String cacheName, boolean originLocal) {
212 //TBD: do we require this.
213 if(log.isDebugEnabled()){
214 log.debug("RoutingTableUpdates: entryCreated routeId = "+key
215 + " cacheName="+cacheName
221 * Called anytime a given entry is updated
223 * @param key Key for the entry modified
224 * @param new_value the new value the key will have
225 * @param cacheName name of the cache for which update has been
227 * @param originLocal true if the event is generated from this
231 public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
232 if(log.isDebugEnabled()){
233 log.debug("RoutingTableUpdates: entryUpdated routeId = "+key
234 + ",value = "+ new_value
235 + " ,cacheName="+cacheName
238 for(RouteChangeListener rcl:routeChangeListeners){
239 rcl.onRouteUpdated(key, new_value);
244 * Called anytime a given key is removed from the
245 * ConcurrentHashMap we are listening to.
247 * @param key Key of the entry removed
248 * @param cacheName name of the cache for which update has been
250 * @param originLocal true if the event is generated from this
254 public void entryDeleted(I key, String cacheName, boolean originLocal) {
255 if(log.isDebugEnabled()){
256 log.debug("RoutingTableUpdates: entryUpdated routeId = "+key
257 + " local = "+ originLocal
258 + " cacheName="+cacheName
261 for(RouteChangeListener rcl:routeChangeListeners){
262 rcl.onRouteDeleted(key);