Bug 1764 - moved Session related interfaces to openflowplugin-api
[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.openflow.md.core.session.SessionContext;
23 import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionListener;
24 import org.opendaylight.openflowplugin.api.openflow.md.core.session.SwitchSessionKeyOF;
25 import org.opendaylight.openflowplugin.api.statistics.MessageSpy;
26 import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor;
27 import org.opendaylight.openflowplugin.api.openflow.md.core.IMDMessageTranslator;
28 import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider;
29 import org.opendaylight.openflowplugin.api.openflow.md.queue.PopListener;
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.concepts.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 instace
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.warn("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.warn("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
143             context.setValid(true);
144         }
145     }
146
147     @Override
148     public void invalidateAuxiliary(SwitchSessionKeyOF sessionKey,
149                                     SwitchConnectionDistinguisher connectionCookie) {
150         SessionContext context = getSessionContext(sessionKey);
151         invalidateAuxiliary(context, connectionCookie, true);
152     }
153
154     /**
155      * @param context
156      * @param connectionCookie
157      * @param disconnect       true if auxiliary connection is to be disconnected
158      */
159     private static void invalidateAuxiliary(SessionContext context, SwitchConnectionDistinguisher connectionCookie,
160                                             boolean disconnect) {
161         if (context == null) {
162             LOG.warn("context for invalidation not found");
163         } else {
164             ConnectionConductor auxiliaryConductor = context.removeAuxiliaryConductor(connectionCookie);
165             if (auxiliaryConductor == null) {
166                 LOG.warn("auxiliary conductor not found");
167             } else {
168                 if (disconnect) {
169                     auxiliaryConductor.disconnect();
170                 }
171             }
172         }
173     }
174
175     @Override
176     public void invalidateOnDisconnect(ConnectionConductor conductor) {
177         if (conductor.getAuxiliaryKey() == null) {
178             invalidateDeadSessionContext(conductor.getSessionContext());
179             // TODO:: notify listeners
180         } else {
181             invalidateAuxiliary(conductor.getSessionContext(), conductor.getAuxiliaryKey(), false);
182         }
183     }
184
185     @Override
186     public void setTranslatorMapping(Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> translatorMapping) {
187         this.translatorMapping = translatorMapping;
188     }
189
190     @Override
191     public ListenerRegistration<SessionListener> registerSessionListener(SessionListener listener) {
192         LOG.debug("registerSessionListener");
193         return sessionListeners.register(listener);
194     }
195
196     private final SessionListener sessionNotifier = new SessionListener() {
197
198         @Override
199         public void onSessionAdded(SwitchSessionKeyOF sessionKey, SessionContext context) {
200             for (ListenerRegistration<SessionListener> listener : sessionListeners) {
201                 try {
202                     listener.getInstance().onSessionAdded(sessionKey, context);
203                 } catch (Exception e) {
204                     LOG.error("Unhandled exeption occured while invoking onSessionAdded on listener", e);
205                 }
206             }
207         }
208
209         @Override
210         public void onSessionRemoved(SessionContext context) {
211             for (ListenerRegistration<SessionListener> listener : sessionListeners) {
212                 try {
213                     listener.getInstance().onSessionRemoved(context);
214                 } catch (Exception e) {
215                     LOG.error("Unhandled exeption occured while invoking onSessionRemoved on listener", e);
216                 }
217             }
218         }
219     };
220     private MessageSpy<DataContainer> messageSpy;
221     private ExtensionConverterProvider extensionConverterProvider;
222
223
224     @Override
225     public Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> getTranslatorMapping() {
226         return this.translatorMapping;
227     }
228
229     @Override
230     public void setNotificationProviderService(
231             NotificationProviderService notificationProviderService) {
232         this.notificationProviderService = notificationProviderService;
233
234     }
235
236     @Override
237     public DataBroker getDataBroker() {
238         return dataBroker;
239     }
240
241     @Override
242     public void setDataBroker(DataBroker dataBroker) {
243         this.dataBroker = dataBroker;
244
245     }
246
247     @Override
248     public NotificationProviderService getNotificationProviderService() {
249         return notificationProviderService;
250     }
251
252     @Override
253     public Map<Class<? extends DataObject>, Collection<PopListener<DataObject>>> getPopListenerMapping() {
254         return popListenerMapping;
255     }
256
257     @Override
258     public void setPopListenerMapping(
259             Map<Class<? extends DataObject>, Collection<PopListener<DataObject>>> popListenerMapping) {
260         this.popListenerMapping = popListenerMapping;
261     }
262
263     @Override
264     public void close() {
265         LOG.debug("close");
266         sessionListeners = null;
267         synchronized (sessionLot) {
268             for (SessionContext sessionContext : sessionLot.values()) {
269                 sessionContext.getPrimaryConductor().disconnect();
270             }
271             // TODO: handle timeouted shutdown
272             rpcPool.shutdown();
273         }
274     }
275
276     @Override
277     public void setRpcPool(ListeningExecutorService rpcPool) {
278         this.rpcPool = rpcPool;
279     }
280
281     @Override
282     public ListeningExecutorService getRpcPool() {
283         return rpcPool;
284     }
285
286     @Override
287     public void setMessageSpy(MessageSpy<DataContainer> messageSpy) {
288         this.messageSpy = messageSpy;
289     }
290
291     @Override
292     public MessageSpy<DataContainer> getMessageSpy() {
293         return messageSpy;
294     }
295
296     @Override
297     public void setExtensionConverterProvider(
298             ExtensionConverterProvider extensionConverterProvider) {
299         this.extensionConverterProvider = extensionConverterProvider;
300     }
301
302     /**
303      * @return the extensionConverterProvider
304      */
305     @Override
306     public ExtensionConverterProvider getExtensionConverterProvider() {
307         return extensionConverterProvider;
308     }
309 }