tomcat Session manager to support clustering using infinispan
[controller.git] / opendaylight / samples / clustersession / src / main / java / org / opendaylight / controller / clustersession / impl / ClusterSessionServiceImpl.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  */
5 package org.opendaylight.controller.clustersession.impl;
6
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.EnumSet;
10 import java.util.Enumeration;
11 import java.util.HashMap;
12 import java.util.concurrent.ConcurrentMap;
13
14 import org.apache.catalina.Session;
15 import org.apache.catalina.util.SessionIdGenerator;
16 import org.opendaylight.controller.clustering.services.CacheConfigException;
17 import org.opendaylight.controller.clustering.services.CacheExistException;
18 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
19 import org.opendaylight.controller.clustering.services.IClusterServices;
20 import org.opendaylight.controller.clustersession.ClusterSession;
21 import org.opendaylight.controller.clustersession.ClusterSessionData;
22 import org.opendaylight.controller.clustersession.ClusterSessionManager;
23 import org.opendaylight.controller.clustersession.ClusterSessionUtil;
24 import org.opendaylight.controller.clustersession.service.ClusterSessionService;
25 import org.osgi.framework.BundleContext;
26 import org.osgi.framework.FrameworkUtil;
27 import org.osgi.framework.ServiceReference;
28 import org.osgi.util.tracker.ServiceTracker;
29 import org.osgi.util.tracker.ServiceTrackerCustomizer;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * Implementation to persist and retrieve session data from infinispan cache
35  * @author harman singh
36  *
37  */
38 public class ClusterSessionServiceImpl implements ClusterSessionService,
39   ServiceTrackerCustomizer<IClusterGlobalServices, IClusterGlobalServices>{
40
41   private IClusterGlobalServices clusterGlobalServices = null;
42   private static final Logger LOGGER = LoggerFactory.getLogger(ClusterSessionServiceImpl.class);
43   private ConcurrentMap<String, ClusterSessionData> sessions = null;
44   private static final String SESSION_CACHE = "customSessionManager.sessionData";
45   private ClusterSessionManager manager = null;
46   private SessionIdGenerator sessionIdGenerator = null;
47   private BundleContext context = null;
48   private ServiceTracker<IClusterGlobalServices, IClusterGlobalServices> clusterTracker;
49   public ClusterSessionServiceImpl(ClusterSessionManager manager) {
50     this.manager = manager;
51   }
52   /**
53    * This method initialize the cluster service of opendaylight and
54    * create a cache map in infinispan
55    */
56
57   @Override
58   public void startInternal(SessionIdGenerator sessionIdGenerator){
59     this.sessionIdGenerator = sessionIdGenerator;
60     context = FrameworkUtil.getBundle(ClusterSessionManager.class).getBundleContext();
61     getClusterService();
62     createCache();
63   }
64
65   /**
66    * Removes the cluster service tracker while shut down
67    */
68   @Override
69   public void stopInternal(){
70     if(clusterTracker != null){
71       clusterTracker.close();
72     }
73   }
74   /**
75    * {@inheritDoc}
76    */
77   @Override
78   public Session findSession(final String id){
79     if(id == null) {
80       return null;
81     }
82     if(sessions == null) {
83       LOGGER.debug("Session cache not present, try to create.");
84       createCache();
85       return null;
86     }
87     ClusterSessionData sessionData = sessions.get(id);
88     if(sessionData != null) {
89       LOGGER.debug("SESSION FOUND : ", id);
90     } else {
91       LOGGER.debug("SESSION NOTFOUND : ", id);
92     }
93     return ClusterSessionUtil.getDeserializedSession(sessionData, this, this.manager);
94   }
95
96   /**
97    * {@inheritDoc}
98    */
99   @Override
100   public Session[] findSessions() {
101     if(sessions == null) {
102       LOGGER.debug("Session cache not present, try to create.");
103       createCache();
104       return new Session[0];
105     }
106     Collection<ClusterSessionData> sessionDataList = sessions.values();
107     ArrayList<ClusterSession> sessionList = new ArrayList<ClusterSession>();
108     for(ClusterSessionData sessionData : sessionDataList){
109       sessionList.add(ClusterSessionUtil.getDeserializedSession(sessionData, this, this.manager));
110     }
111     return sessionList.toArray(new Session[0]);
112   }
113
114   /**
115    * {@inheritDoc}
116    */
117   @Override
118   public void removeSession(final String id){
119     if(sessions == null) {
120       LOGGER.debug("Session cache not present, try to create.");
121       createCache();
122       return;
123     }
124     sessions.remove(id);
125   }
126
127   /**
128    * {@inheritDoc}
129    */
130   @Override
131   public void expireSession(final String id){
132     if(sessions == null) {
133       LOGGER.debug("Session cache not present, try to create.");
134       createCache();
135       return;
136     }
137     ClusterSessionData sessionData = sessions.get(id);
138     if(sessionData != null) {
139       sessionData.getSession().expire();
140       removeSession(id);
141     }
142   }
143
144   /**
145    * {@inheritDoc}
146    */
147   @Override
148   public Session createSession(final String sessionId){
149     if(sessions == null) {
150       LOGGER.debug("Session cache not present, try to create.");
151       createCache();
152       return null;
153     }
154     Session session = createEmptySession();
155     session.setNew(true);
156     session.setValid(true);
157     session.setCreationTime(System.currentTimeMillis());
158     String id = sessionId;
159     if (id == null) {
160       id = generateSessionId();
161     }
162     session.setId(id);
163     return session;
164   }
165
166   /**
167    * {@inheritDoc}
168    */
169   @Override
170   public void addSession(final ClusterSession session){
171     if(sessions == null) {
172       LOGGER.debug("Session cache not present, try to create.");
173       createCache();
174       return;
175     }
176     ClusterSessionData sessionData = ClusterSessionUtil.getSerializableSession(session);
177     sessions.put(session.getId(), sessionData);
178   }
179
180   /**
181    * {@inheritDoc}
182    */
183   @Override
184   public Session createEmptySession(){
185     return getNewSession();
186   }
187
188   /**
189    * Returns information about the session with the given session id.
190    *
191    * <p>The session information is organized as a HashMap, mapping
192    * session attribute names to the String representation of their values.
193    *
194    * @param sessionId Session id
195    *
196    * @return HashMap mapping session attribute names to the String
197    * representation of their values, or null if no session with the
198    * specified id exists, or if the session does not have any attributes
199    */
200   public HashMap<String, String> getSession(String sessionId) {
201     if(sessions == null) {
202       LOGGER.debug("Session cache not present, try to create.");
203       createCache();
204       return null;
205     }
206     ClusterSessionData sessionData = sessions.get(sessionId);
207     if (sessionData == null) {
208       return null;
209     }
210     ClusterSession s = ClusterSessionUtil.getDeserializedSession(sessionData, this, this.manager);
211     Enumeration<String> ee = s.getAttributeNames();
212     if (ee == null || !ee.hasMoreElements()) {
213       return null;
214     }
215     HashMap<String, String> map = new HashMap<String, String>();
216     while (ee.hasMoreElements()) {
217       String attrName = ee.nextElement();
218       map.put(attrName, s.getAttribute(attrName).toString());
219     }
220     return map;
221   }
222
223   /**
224    * {@inheritDoc}
225    */
226   @Override
227   public void updateSession(ClusterSession session) {
228     if(sessions == null) {
229       LOGGER.debug("Session cache not present, try to create.");
230       createCache();
231       return;
232     }
233     if(session.getId() != null && sessions.get(session.getId()) != null){
234       ClusterSessionData sessionData = ClusterSessionUtil.getSerializableSession(session);
235       sessions.put(session.getId(), sessionData);
236     }
237   }
238
239   @Override
240   public IClusterGlobalServices addingService(ServiceReference<IClusterGlobalServices> reference) {
241       if (clusterGlobalServices == null) {
242         this.clusterGlobalServices = context.getService(reference);
243         createCache();
244         return clusterGlobalServices;
245       }
246       return null;
247   }
248
249   @Override
250   public void modifiedService(ServiceReference<IClusterGlobalServices> reference, IClusterGlobalServices service) {
251     // This method is added from ServiceTracker interface, We don't have to modify service.
252   }
253
254   @Override
255   public void removedService(ServiceReference<IClusterGlobalServices> reference, IClusterGlobalServices service) {
256       if (clusterGlobalServices == service) {
257           clusterGlobalServices = null;
258       }
259   }
260
261   /*
262    * Return an instance of Standard Session object with current session manager
263    */
264   private ClusterSession getNewSession() {
265     return new ClusterSession(this.manager, this);
266   }
267
268   /*
269    * Generate and return a new session identifier.
270    */
271   private String generateSessionId() {
272     String result = null;
273     do {
274       result = sessionIdGenerator.generateSessionId();
275     } while (sessions.containsKey(result));
276     return result;
277   }
278
279   private void createCache() {
280     allocateCache();
281     retrieveCache();
282   }
283
284   /*
285    * This is a fragment bundle, so We can't use Activator to set Service.
286    * This is the alternative to get registered clustered service
287    */
288   private void getClusterService(){
289     if (context != null) {
290       clusterTracker = new ServiceTracker<>(context, IClusterGlobalServices.class, this);
291       clusterTracker.open();
292     }
293   }
294
295   /*
296    * Allocate space in infinispan to persist session data
297    */
298   private void allocateCache() {
299     if (clusterGlobalServices == null) {
300       LOGGER.trace("un-initialized clusterGlobalService, can't create cache");
301       return;
302     }
303     try {
304       clusterGlobalServices.createCache(SESSION_CACHE,
305           EnumSet.of(IClusterServices.cacheMode.SYNC , IClusterServices.cacheMode.TRANSACTIONAL));
306
307     } catch (CacheConfigException cce) {
308       LOGGER.error("Cache configuration invalid - check cache mode", cce.toString());
309     } catch (CacheExistException ce) {
310       LOGGER.debug("Skipping cache creation as already present", ce.toString());
311     }
312   }
313
314   /*
315    * Fetch cached session data map object from infinispan
316    */
317   @SuppressWarnings("unchecked")
318   private void retrieveCache(){
319     if (clusterGlobalServices == null) {
320       LOGGER.trace("un-initialized clusterGlobalService, can't retrieve cache");
321       return;
322     }
323     sessions = (ConcurrentMap<String, ClusterSessionData>)clusterGlobalServices.getCache(SESSION_CACHE);
324     if(sessions == null){
325       LOGGER.warn("Failed to get session cache");
326     }
327   }
328 }