BUG-1075: ingress back pressure
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / session / SessionManagerOFImpl.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.openflowplugin.openflow.md.core.session;
10
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.concurrent.ConcurrentHashMap;
17
18 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
19 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
20 import org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductor;
21 import org.opendaylight.openflowplugin.openflow.md.core.IMDMessageTranslator;
22 import org.opendaylight.openflowplugin.openflow.md.core.SwitchConnectionDistinguisher;
23 import org.opendaylight.openflowplugin.openflow.md.core.TranslatorKey;
24 import org.opendaylight.openflowplugin.openflow.md.queue.MessageSpy;
25 import org.opendaylight.openflowplugin.openflow.md.queue.PopListener;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
27 import org.opendaylight.yangtools.concepts.ListenerRegistration;
28 import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
29 import org.opendaylight.yangtools.yang.binding.DataContainer;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import com.google.common.util.concurrent.ListeningExecutorService;
35
36 /**
37  * @author mirehak
38  */
39 public class SessionManagerOFImpl implements SessionManager {
40
41     protected static final Logger LOG = LoggerFactory.getLogger(SessionManagerOFImpl.class);
42     private static SessionManagerOFImpl instance;
43     private ConcurrentHashMap<SwitchSessionKeyOF, SessionContext> sessionLot;
44     private Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> translatorMapping;
45     private Map<Class<? extends DataObject>, Collection<PopListener<DataObject>>> popListenerMapping;
46
47     protected ListenerRegistry<SessionListener> sessionListeners;
48     private NotificationProviderService notificationProviderService;
49
50     private DataProviderService dataProviderService;
51     private ListeningExecutorService rpcPool;
52     
53
54     /**
55      * @return singleton instance
56      */
57     public static SessionManager getInstance() {
58         if (instance == null) {
59             synchronized (SessionContextOFImpl.class) {
60                 if (instance == null) {
61                     instance = new SessionManagerOFImpl();
62                 }
63             }
64         }
65         return instance;
66     }
67     
68     /**
69      * close and release singleton instace
70      */
71     public static void releaseInstance() {
72         if (instance != null) {
73             synchronized (SessionManagerOFImpl.class) {
74                 if (instance != null) {
75                     instance.close();
76                     instance = null;
77                 }
78             }
79         }
80     }
81
82     private SessionManagerOFImpl() {
83         LOG.debug("singleton creating");
84         sessionLot = new ConcurrentHashMap<>();
85         sessionListeners = new ListenerRegistry<>();
86     }
87
88     @Override
89     public SessionContext getSessionContext(SwitchSessionKeyOF sessionKey) {
90         return sessionLot.get(sessionKey);
91     }
92
93     @Override
94     public void invalidateSessionContext(SwitchSessionKeyOF sessionKey) {
95         SessionContext context = getSessionContext(sessionKey);
96         if (context == null) {
97             LOG.warn("context for invalidation not found");
98         } else {
99             for (Entry<SwitchConnectionDistinguisher, ConnectionConductor> auxEntry : context.getAuxiliaryConductors()) {
100                 invalidateAuxiliary(sessionKey, auxEntry.getKey());
101             }
102             context.getPrimaryConductor().disconnect();
103             context.setValid(false);
104             removeSessionContext(context);
105             // TODO:: notify listeners
106         }
107     }
108
109     private void invalidateDeadSessionContext(SessionContext sessionContext) {
110         if (sessionContext == null) {
111             LOG.warn("context for invalidation not found");
112         } else {
113             for (Entry<SwitchConnectionDistinguisher, ConnectionConductor> auxEntry : sessionContext
114                     .getAuxiliaryConductors()) {
115                 invalidateAuxiliary(sessionContext, auxEntry.getKey(), true);
116             }
117             sessionContext.setValid(false);
118             removeSessionContext(sessionContext);
119             // TODO:: notify listeners
120         }
121     }
122
123     private void removeSessionContext(SessionContext sessionContext) {
124         if (LOG.isDebugEnabled()) {
125             LOG.debug("removing session: {}", Arrays.toString(sessionContext.getSessionKey().getId()));
126         }
127         sessionLot.remove(sessionContext.getSessionKey(), sessionContext);
128         sessionNotifier.onSessionRemoved(sessionContext);
129     }
130
131     @Override
132     public void addSessionContext(SwitchSessionKeyOF sessionKey, SessionContext context) {
133         sessionLot.put(sessionKey, context);
134
135         sessionNotifier.onSessionAdded(sessionKey, context);
136
137     }
138
139     @Override
140     public void invalidateAuxiliary(SwitchSessionKeyOF sessionKey,
141             SwitchConnectionDistinguisher connectionCookie) {
142         SessionContext context = getSessionContext(sessionKey);
143         invalidateAuxiliary(context, connectionCookie, true);
144     }
145
146     /**
147      * @param context
148      * @param connectionCookie
149      * @param disconnect
150      *            true if auxiliary connection is to be disconnected
151      */
152     private static void invalidateAuxiliary(SessionContext context, SwitchConnectionDistinguisher connectionCookie,
153             boolean disconnect) {
154         if (context == null) {
155             LOG.warn("context for invalidation not found");
156         } else {
157             ConnectionConductor auxiliaryConductor = context.removeAuxiliaryConductor(connectionCookie);
158             if (auxiliaryConductor == null) {
159                 LOG.warn("auxiliary conductor not found");
160             } else {
161                 if (disconnect) {
162                     auxiliaryConductor.disconnect();
163                 }
164             }
165         }
166     }
167
168     @Override
169     public void invalidateOnDisconnect(ConnectionConductor conductor) {
170         if (conductor.getAuxiliaryKey() == null) {
171             invalidateDeadSessionContext(conductor.getSessionContext());
172             // TODO:: notify listeners
173         } else {
174             invalidateAuxiliary(conductor.getSessionContext(), conductor.getAuxiliaryKey(), false);
175         }
176     }
177
178     @Override
179     public void setTranslatorMapping(Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> translatorMapping) {
180         this.translatorMapping = translatorMapping;
181     }
182
183     @Override
184     public ListenerRegistration<SessionListener> registerSessionListener(SessionListener listener) {
185         LOG.debug("registerSessionListener");
186         return sessionListeners.register(listener);
187     }
188
189     private final SessionListener sessionNotifier = new SessionListener() {
190
191         @Override
192         public void onSessionAdded(SwitchSessionKeyOF sessionKey, SessionContext context) {
193             for (ListenerRegistration<SessionListener> listener : sessionListeners) {
194                 try {
195                     listener.getInstance().onSessionAdded(sessionKey, context);
196                 } catch (Exception e) {
197                     LOG.error("Unhandled exeption occured while invoking onSessionAdded on listener", e);
198                 }
199             }
200         }
201
202         @Override
203         public void onSessionRemoved(SessionContext context) {
204             for (ListenerRegistration<SessionListener> listener : sessionListeners) {
205                 try {
206                     listener.getInstance().onSessionRemoved(context);
207                 } catch (Exception e) {
208                     LOG.error("Unhandled exeption occured while invoking onSessionRemoved on listener", e);
209                 }
210             }
211         }
212     };
213     private MessageSpy<DataContainer> messageSpy;
214     
215
216     @Override
217     public Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> getTranslatorMapping() {
218         return this.translatorMapping;
219     }
220
221     @Override
222     public void setNotificationProviderService(
223             NotificationProviderService notificationProviderService) {
224         this.notificationProviderService = notificationProviderService;
225
226     }
227
228     @Override
229     public DataProviderService getDataProviderService() {
230         return dataProviderService;
231     }
232
233     @Override
234     public void setDataProviderService(DataProviderService dataServiceProvider) {
235         this.dataProviderService = dataServiceProvider;
236
237     }
238
239     @Override
240     public NotificationProviderService getNotificationProviderService() {
241         return notificationProviderService;
242     }
243
244     @Override
245     public Map<Class<? extends DataObject>, Collection<PopListener<DataObject>>> getPopListenerMapping() {
246         return popListenerMapping;
247     }
248
249     @Override
250     public void setPopListenerMapping(
251             Map<Class<? extends DataObject>, Collection<PopListener<DataObject>>> popListenerMapping) {
252         this.popListenerMapping = popListenerMapping;
253     }
254     
255     @Override
256     public void close() {
257         LOG.debug("close");
258         sessionListeners = null;
259         synchronized (sessionLot) {
260             for (SessionContext sessionContext : sessionLot.values()) {
261                 sessionContext.getPrimaryConductor().disconnect();
262             }
263             // TODO: handle timeouted shutdown
264             rpcPool.shutdown();
265         }
266     }
267
268     @Override
269     public void setRpcPool(ListeningExecutorService rpcPool) {
270         this.rpcPool = rpcPool;
271     }
272     
273     @Override
274     public ListeningExecutorService getRpcPool() {
275         return rpcPool;
276     }
277     
278     @Override
279     public void setMessageSpy(MessageSpy<DataContainer> messageSpy) {
280         this.messageSpy = messageSpy;
281     }
282     
283     @Override
284     public MessageSpy<DataContainer> getMessageSpy() {
285         return messageSpy;
286     }
287 }