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