001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.main;
029
030import org.opencms.file.CmsRequestContext;
031import org.opencms.util.CmsUUID;
032
033import java.io.Serializable;
034
035import org.apache.commons.collections.Buffer;
036import org.apache.commons.collections.BufferUtils;
037import org.apache.commons.collections.buffer.UnboundedFifoBuffer;
038
039/**
040 * Stores information about a user that has authenticated himself the OpenCms security system.<p>
041 *
042 * This object is used to provide information about all authenticated users in the system
043 * with the {@link org.opencms.main.CmsSessionManager}.<p>
044 *
045 * This object is available for all authenticated users after login.
046 * If a user has not logged in, he may have a session on the servlet engine,
047 * but he will have no session info object attached. For example the "Guest" user
048 * may have multiple sessions, but no session info is created for him.<p>
049 *
050 * @since 6.0.0
051 */
052public class CmsSessionInfo implements Comparable<CmsSessionInfo>, Serializable {
053
054    /** Name of the http session attribute the OpenCms session id is stored in. */
055    public static final String ATTRIBUTE_SESSION_ID = "__org.opencms.main.CmsSessionInfo#m_sessionId";
056
057    /** Maximum size of the broadcast queue for one user. */
058    public static final int QUEUE_SIZE = 10;
059
060    /** Serial version UID required for safe serialization. */
061    private static final long serialVersionUID = 927301527031117920L;
062
063    /** The broadcast queue buffer for the user of this session info. */
064    private transient Buffer m_broadcastQueue;
065
066    /** The optional label of the client this session was created for. */
067    private String m_clientLabel;
068
069    /** The maximum time, in seconds, this session info is allowed to be inactive. */
070    private int m_maxInactiveInterval;
071
072    /** The fully qualified name of the organizational unit. */
073    private String m_ouFqn;
074
075    /** The current project id of the user. */
076    private CmsUUID m_projectId;
077
078    /** The id of the (http) session this session info belongs to. */
079    private CmsUUID m_sessionId;
080
081    /** The current site of the user. */
082    private String m_siteRoot;
083
084    /** The time this session info was created. */
085    private long m_timeCreated;
086
087    /** The time this session info was last updated. */
088    private long m_timeUpdated;
089
090    /** The time of the last user action. */
091    private long m_timeLastAction;
092
093    /** The id of user to which this session info belongs. */
094    private CmsUUID m_userId;
095
096    /**
097     * Creates a new CmsSessionInfo object.<p>
098     *
099     * @param context the user context to create this session info for
100     * @param sessionId OpenCms id of the (http) session this session info belongs to
101     * @param maxInactiveInterval the maximum time, in seconds, this session info is allowed to be inactive
102     */
103    public CmsSessionInfo(CmsRequestContext context, CmsUUID sessionId, int maxInactiveInterval) {
104
105        m_timeCreated = System.currentTimeMillis();
106        m_sessionId = sessionId;
107        m_maxInactiveInterval = maxInactiveInterval;
108        m_userId = context.getCurrentUser().getId();
109        m_clientLabel = (String)context.getAttribute(CmsRequestContext.ATTRIBUTE_CLIENT_LABEL);
110        update(context);
111    }
112
113    /**
114     * Returns a string for given time.<p>
115     *
116     * @param time as timestamp
117     * @return string array containing string for hours, minutes, seconds
118     */
119    public static String[] getHourMinuteSecondTimeString(long time) {
120
121        int hours = (int)time / (1000 * 60 * 60);
122        int min = (int)(time - (hours * 1000 * 60 * 60)) / (1000 * 60);
123        int sec = (int)(time - (hours * 1000 * 60 * 60) - (min * 1000 * 60)) / 1000;
124
125        return new String[] {getTwoDigitsString(hours), getTwoDigitsString(min), getTwoDigitsString(sec)};
126    }
127
128    /**
129     * Formats an integer to a two chars string.<p>
130     *
131     * @param number to be formatted
132     * @return the string representation
133     */
134    private static String getTwoDigitsString(int number) {
135
136        return number < 10 ? "0" + number : String.valueOf(number);
137    }
138
139    /**
140     * Allows sorting session info according to the user names.<p>
141     *
142     * @see java.lang.Comparable#compareTo(java.lang.Object)
143     */
144    public int compareTo(CmsSessionInfo obj) {
145
146        if (obj == this) {
147            return 0;
148        }
149        return m_userId.compareTo(obj.getUserId());
150    }
151
152    /**
153     * @see java.lang.Object#equals(java.lang.Object)
154     */
155    @Override
156    public boolean equals(Object obj) {
157
158        if (obj == this) {
159            return true;
160        }
161        if (obj instanceof CmsSessionInfo) {
162            return m_userId.equals(((CmsSessionInfo)obj).getUserId());
163        }
164        return false;
165    }
166
167    /**
168     * Gets the age of the session formattet as HOURS:MINUTES.<p>
169     *
170     * @return string representation of session age
171     */
172    public String getAgeOfSession() {
173
174        String[] ret = getHourMinuteSecondTimeString(System.currentTimeMillis() - m_timeCreated);
175        return ret[0] + ":" + ret[1];
176
177    }
178
179    /**
180     * Returns the broadcast queue of the user to which this session info belongs.<p>
181     *
182     * @return the broadcast queue of the user to which this session info belongs
183     */
184    public Buffer getBroadcastQueue() {
185
186        if (m_broadcastQueue == null) {
187            m_broadcastQueue = BufferUtils.synchronizedBuffer(new UnboundedFifoBuffer(QUEUE_SIZE));
188        }
189        return m_broadcastQueue;
190    }
191
192    /**
193     * Returns the optional label of the client this session was created for, taken once at session
194     * creation from the {@link CmsRequestContext#ATTRIBUTE_CLIENT_LABEL} context attribute.<p>
195     *
196     * @return the client label, or <code>null</code> for a session created without one
197     */
198    public String getClientLabel() {
199
200        return m_clientLabel;
201    }
202
203    /**
204     * Returns the maximum time, in seconds, this session info is allowed to be inactive.<p>
205     *
206     * The inactive time is the time since the last call to the {@link #update(CmsRequestContext)}
207     * method. If the inactive time is greater then the maximum allowed time, this
208     * session info will be removed from the session manager.<p>
209     *
210     * @return the maximum time, in seconds, this session info is allowed to be inactive
211     *
212     * @see jakarta.servlet.http.HttpSession#getMaxInactiveInterval()
213     */
214    public int getMaxInactiveInterval() {
215
216        return m_maxInactiveInterval;
217    }
218
219    /**
220     * Returns the fully qualified name of the organizational unit for this session.<p>
221     *
222     * @return the fully qualified name of the organizational unit for this session
223     */
224    public String getOrganizationalUnitFqn() {
225
226        return m_ouFqn;
227    }
228
229    /**
230     * Returns the id of the project of the user.<p>
231     *
232     * @return the id of the project
233     */
234    public CmsUUID getProject() {
235
236        return m_projectId;
237    }
238
239    /**
240     * Returns the id of the OpenCms (http) session this session info belongs to.<p>
241     *
242     * @return the id of the OpenCms (http) session this session info belongs to
243     *
244     * @see jakarta.servlet.http.HttpSession#getId()
245     */
246    public CmsUUID getSessionId() {
247
248        return m_sessionId;
249    }
250
251    /**
252     * Returns the current site root of the user.<p>
253     *
254     * @return the current site root of the user
255     */
256    public String getSiteRoot() {
257
258        return m_siteRoot;
259    }
260
261    /**
262     * Returns the time, in milliseconds, this session has been active,
263     * that is the time of the last update minus the creation time.<p>
264     *
265     * @return the time, in milliseconds, this session has been active
266     */
267    public long getTimeActive() {
268
269        return m_timeUpdated - m_timeCreated;
270    }
271
272    /**
273     * Returns the time this session info was created.<p>
274     *
275     * @return the time this session info was created
276     */
277    public long getTimeCreated() {
278
279        return m_timeCreated;
280    }
281
282    /**
283     * Returns the time of the last user action.<p>
284     *
285     * @return the list user action time
286     */
287    public long getTimeLastAction() {
288
289        return m_timeLastAction;
290    }
291
292    /**
293     * Returns the time this session info was last updated.<p>
294     *
295     * @return the time this session info was last updated
296     */
297    public long getTimeUpdated() {
298
299        return m_timeUpdated;
300    }
301
302    /**
303     * Returns the id of the user to which this session info belongs.<p>
304     *
305     * @return the id of the user to which this session info belongs
306     */
307    public CmsUUID getUserId() {
308
309        return m_userId;
310    }
311
312    /**
313     * @see java.lang.Object#hashCode()
314     */
315    @Override
316    public int hashCode() {
317
318        return m_userId.hashCode();
319    }
320
321    /**
322     * Returns <code>true</code> if this session info has expired, that
323     * is it has not been updated in the time set by the maximum inactivity interval.<p>
324     *
325     * @return <code>true</code> if this session info has expired
326     */
327    public boolean isExpired() {
328
329        return ((System.currentTimeMillis() - m_timeUpdated) / 1000) > m_maxInactiveInterval;
330    }
331
332    /**
333     * @see java.lang.Object#toString()
334     */
335    @Override
336    public String toString() {
337
338        StringBuffer str = new StringBuffer(64);
339        str.append("[");
340        str.append("sessionId: ").append(m_sessionId).append(", ");
341        str.append("userId: ").append(m_userId).append(", ");
342        str.append("projectId: ").append(m_projectId).append(", ");
343        str.append("siteRoot: ").append(m_siteRoot).append(", ");
344        str.append("timeCreated: ").append(m_timeCreated).append(", ");
345        str.append("timeUpdated: ").append(m_timeUpdated).append(", ");
346        str.append("maxInactiveInterval: ").append(m_maxInactiveInterval);
347        str.append("ouFqn: ").append(m_ouFqn);
348        str.append("]");
349        return str.toString();
350    }
351
352    /**
353     * Sets the id of the current project of the user of this session info.<p>
354     *
355     * @param projectId the project id to set
356     */
357    protected void setProject(CmsUUID projectId) {
358
359        m_projectId = projectId;
360    }
361
362    /**
363     * Updates the session info object with the information from
364     * the given request context.<p>
365     *
366     * @param context the request context to update the session with
367     */
368    protected void update(CmsRequestContext context) {
369
370        update(context, false);
371    }
372
373    /**
374     * Updates the session info object with the information from
375     * the given request context.<p>
376     *
377     * @param context the request context to update the session with
378     * @param isHeartBeatRequest in case of heart beat requests
379     */
380    protected void update(CmsRequestContext context, boolean isHeartBeatRequest) {
381
382        m_timeUpdated = System.currentTimeMillis();
383        if (!isHeartBeatRequest) {
384            m_timeLastAction = m_timeUpdated;
385        }
386        m_siteRoot = context.getSiteRoot();
387        setProject(context.getCurrentProject().getUuid());
388        m_ouFqn = context.getOuFqn();
389    }
390}