001package org.apache.turbine.services.session;
002
003
004/*
005 * Licensed to the Apache Software Foundation (ASF) under one
006 * or more contributor license agreements.  See the NOTICE file
007 * distributed with this work for additional information
008 * regarding copyright ownership.  The ASF licenses this file
009 * to you under the Apache License, Version 2.0 (the
010 * "License"); you may not use this file except in compliance
011 * with the License.  You may obtain a copy of the License at
012 *
013 *   http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing,
016 * software distributed under the License is distributed on an
017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018 * KIND, either express or implied.  See the License for the
019 * specific language governing permissions and limitations
020 * under the License.
021 */
022
023
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.concurrent.ConcurrentHashMap;
027import java.util.concurrent.ConcurrentMap;
028
029import javax.servlet.http.HttpSession;
030
031import org.apache.turbine.om.security.User;
032import org.apache.turbine.services.TurbineBaseService;
033
034/**
035 * The SessionService allows thread-safe access to the current
036 * sessions of the current context.  The session objects that are
037 * cached by this service are obtained through a listener, which must
038 * be configured via your web application's <code>web.xml</code>
039 * deployment descriptor as follows:
040 *
041 * <pre>
042 * &lt;listener&gt;
043 *   &lt;listener-class&gt;
044 *     org.apache.turbine.session.SessionListener
045 *   &lt;/listener-class&gt;
046 * &lt;/listener&gt;
047 * </pre>
048 *
049 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
050 * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
051 * @since 2.3
052 * @version $Id$
053 * @see org.apache.turbine.services.session.SessionListener
054 */
055public class TurbineSessionService
056        extends TurbineBaseService
057        implements SessionService
058{
059    /** Map of active sessions */
060    private ConcurrentMap<String, HttpSession> activeSessions;
061
062    /**
063     * Gets a list of the active sessions.
064     *
065     * @return A copy of the list of <code>HttpSession</code> objects.
066     */
067    @Override
068    public Collection<HttpSession> getActiveSessions()
069    {
070        return new ArrayList<>(activeSessions.values());
071    }
072
073    /**
074     * Adds a session to the current list.  This method should only be
075     * called by the listener.
076     *
077     * @param session Session to add
078     */
079    @Override
080    public void addSession(HttpSession session)
081    {
082        activeSessions.put(session.getId(), session);
083    }
084
085    /**
086     * Removes a session from the current list.  This method should only be
087     * called by the listener.
088     *
089     * @param session Session to remove
090     */
091    @Override
092    public void removeSession(HttpSession session)
093    {
094        activeSessions.remove(session.getId());
095    }
096
097    /**
098     * Determines if a given user is currently logged in.  The actual
099     * implementation of the User object must implement the equals()
100     * method.  By default, Torque based objects (liek TurbineUser)
101     * have an implementation of equals() that will compare the
102     * result of getPrimaryKey().
103     *
104     * @param user User to check for
105     * @return true if the user is logged in on one of the
106     * active sessions.
107     */
108    @Override
109    public boolean isUserLoggedIn(User user)
110    {
111        return getActiveUsers().contains(user);
112    }
113
114    /**
115     * Gets a collection of all user objects representing the users currently
116     * logged in.  This will exclude any instances of anonymous user that
117     * Turbine will use before the user actually logs on.
118     *
119     * @return A set of {@link org.apache.turbine.om.security.User} objects.
120     */
121    @Override
122    public Collection<User> getActiveUsers()
123    {
124        Collection<User> users;
125        // Pre-allocate a list which won't need expansion more
126        // than once.
127        users = new ArrayList<>((int) (activeSessions.size() * 0.7));
128        for (HttpSession session : activeSessions.values())
129        {
130            User u = getUserFromSession(session);
131            if (u != null && u.hasLoggedIn())
132            {
133                users.add(u);
134            }
135        }
136
137        return users;
138    }
139
140    /**
141     * Gets the User object of the the specified HttpSession.
142     *
143     * @param session The session from which to extract a user.
144     * @return The Turbine User object.
145     */
146    @Override
147    public User getUserFromSession(HttpSession session)
148    {
149        // Not sure of other containers, but Tomcat 5.0.28 sometimes returns
150        // invalid sessions which will result in IllegalStateException when
151        // session.getAttribute() is invoked below.
152        try
153        {
154            return (User) session.getAttribute(User.SESSION_KEY);
155        }
156        catch (IllegalStateException e)
157        {
158            return null;
159        }
160    }
161
162    /**
163     * Gets the HttpSession by the session identifier
164     *
165     * @param sessionId The unique session identifier.
166     * @return The session keyed by the specified identifier.
167     */
168    @Override
169    public HttpSession getSession(String sessionId)
170    {
171        return this.activeSessions.get(sessionId);
172    }
173
174    /**
175     * Get a collection of all session on which the given user
176     * is logged in.
177     *
178     * @param user the user
179     * @return Collection of HtttSession objects
180     */
181    @Override
182    public Collection<HttpSession> getSessionsForUser(User user)
183    {
184        Collection<HttpSession> sessions = new ArrayList<>();
185        for (HttpSession session : activeSessions.values())
186        {
187            User u = this.getUserFromSession(session);
188            if (user.equals(u))
189            {
190                sessions.add(session);
191            }
192        }
193
194        return sessions;
195    }
196
197
198    // ---- Service initialization ------------------------------------------
199
200    /**
201     * Initializes the service
202     */
203    @Override
204    public void init()
205    {
206        this.activeSessions = new ConcurrentHashMap<>();
207
208        setInit(true);
209    }
210
211    /**
212     * Returns to uninitialized state.
213     */
214    @Override
215    public void shutdown()
216    {
217        this.activeSessions = null;
218
219        setInit(false);
220    }
221
222}