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