558c8a80d32b59aaf092a4505e680c9eabb14190
[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.*;
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;
21
22 import javax.transaction.HeuristicMixedException;
23 import javax.transaction.HeuristicRollbackException;
24 import javax.transaction.NotSupportedException;
25 import javax.transaction.RollbackException;
26 import java.util.*;
27 import java.util.concurrent.ConcurrentMap;
28
29 /**
30  * @author: syedbahm
31  */
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";
34
35   private Logger log = LoggerFactory
36             .getLogger(RoutingTableImpl.class);
37
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;
43                                                       
44  public RoutingTableImpl() {
45   }
46
47   @Override
48   public void addRoute(I routeId, R route) throws RoutingTableException {
49        throw new UnsupportedOperationException(" Not implemented yet!");
50   }
51
52   @Override
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!");
56     try {
57
58       Set<R> existingRoute = null;
59       // ok does the global route is already registered ?
60       if ((existingRoute = getRoutes(routeId)) == null) {
61
62           if(log.isDebugEnabled()){
63               log.debug("addGlobalRoute: adding  a new route with id"+ routeId + " and value = "+route);
64           }
65         // lets start a transaction
66         clusterGlobalServices.tbegin();
67         Set<R> routes  = new HashSet<R>();
68         routes.add(route);
69         routingTableCache.put(routeId, routes);
70         clusterGlobalServices.tcommit();
71       } else {
72         throw new DuplicateRouteException(" There is already existing route " + existingRoute);
73       }
74
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);
85     }
86
87   }
88
89   @Override
90   public void removeRoute(I routeId, R route) {
91          throw new UnsupportedOperationException("Not implemented yet!");
92   }
93     @Override
94     public void removeGlobalRoute(I routeId) {
95         routingTableCache.remove(routeId);
96     }
97
98   @Override
99   public Set<R> getRoutes(I routeId) {
100
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);
104   }
105
106   @Override
107   public R getARoute(I routeId) {
108        throw new UnsupportedOperationException("Not implemented yet!");
109   }
110
111   /**
112    * Registers listener for sending any change notification
113    * 
114    * @param listener
115    */
116   @Override
117   public void registerRouteChangeListener(RouteChangeListener listener) {
118       routeChangeListeners.add(listener);
119   }
120
121
122     /**
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
126      */
127   List<RouteChangeListener> getRegisteredRouteChangeListeners(){
128       return routeChangeListeners;
129   }
130
131   public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
132     this.clusterGlobalServices = clusterGlobalServices;
133   }
134
135   public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
136     if(cacheAwareRegistration != null) {
137         cacheAwareRegistration.unregister();
138     }
139     this.clusterGlobalServices = null;
140   }
141
142     /**
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
147      */
148
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?
152
153     // let us check here if the cache already exists -- if so don't create
154     if (!clusterGlobalServices.existCache(
155         ROUTING_TABLE_GLOBAL_CACHE)) {
156
157         if(log.isDebugEnabled()){
158             log.debug("createRoutingTableCache: creating a new routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
159         }
160       routingTableCache = clusterGlobalServices.createCache(
161           ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
162     } else {
163         if(log.isDebugEnabled()){
164             log.debug("createRoutingTableCache: found existing routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
165         }
166       routingTableCache = clusterGlobalServices.getCache(
167           ROUTING_TABLE_GLOBAL_CACHE);
168     }
169
170   }
171
172   /**
173    * Function called by the dependency manager when all the required
174    * dependencies are satisfied
175    * 
176    */
177   void init(Component c) {
178     try {
179
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");
187     }
188   }
189
190
191     /**
192      * Get routing table method is useful for unit testing
193      * <note>It has package scope</note>
194      */
195     ConcurrentMap getRoutingTableCache(){
196         return this.routingTableCache;
197     }
198
199
200       /**
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
203        *
204        * @param key         Key for the entry just created
205        * @param cacheName   name of the cache for which update has been
206        *                    received
207        * @param originLocal true if the event is generated from this
208        *                    node
209        */
210       @Override
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
216                       );
217           }
218       }
219
220       /**
221        * Called anytime a given entry is updated
222        *
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
226        *                    received
227        * @param originLocal true if the event is generated from this
228        *                    node
229        */
230       @Override
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
236                       );
237           }
238           for(RouteChangeListener rcl:routeChangeListeners){
239               rcl.onRouteUpdated(key, new_value);
240           }
241       }
242
243       /**
244        * Called anytime a given key is removed from the
245        * ConcurrentHashMap we are listening to.
246        *
247        * @param key         Key of the entry removed
248        * @param cacheName   name of the cache for which update has been
249        *                    received
250        * @param originLocal true if the event is generated from this
251        *                    node
252        */
253       @Override
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
259                        );
260           }
261           for(RouteChangeListener rcl:routeChangeListeners){
262               rcl.onRouteDeleted(key);
263           }
264       }
265   }