| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.ki.session.mgt; |
| |
| import java.io.Serializable; |
| import java.net.InetAddress; |
| import java.net.UnknownHostException; |
| import java.text.DateFormat; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.ki.session.ExpiredSessionException; |
| import org.apache.ki.session.InvalidSessionException; |
| import org.apache.ki.session.StoppedSessionException; |
| |
| |
| /** |
| * Simple {@link org.apache.ki.session.Session} POJO implementation, intended to be used on the business/server tier. |
| * |
| * @author Les Hazlewood |
| * @since 0.1 |
| */ |
| public class SimpleSession implements ValidatingSession, Serializable { |
| |
| //TODO - complete JavaDoc |
| |
| protected static final long MILLIS_PER_SECOND = 1000; |
| protected static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; |
| protected static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; |
| |
| private transient static final Logger log = LoggerFactory.getLogger(SimpleSession.class); |
| |
| |
| private Serializable id = null; |
| private Date startTimestamp = null; |
| private Date stopTimestamp = null; |
| private Date lastAccessTime = null; |
| private long timeout = DefaultSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT; |
| private boolean expired = false; |
| private InetAddress hostAddress = null; |
| |
| private Map<Object, Object> attributes = null; |
| |
| public SimpleSession() { |
| this(getLocalHost()); |
| } |
| |
| public SimpleSession(InetAddress hostAddress) { |
| this.startTimestamp = new Date(); |
| this.lastAccessTime = startTimestamp; |
| this.hostAddress = hostAddress; |
| } |
| |
| private static InetAddress getLocalHost() { |
| try { |
| return InetAddress.getLocalHost(); |
| } catch (UnknownHostException e) { |
| throw new IllegalStateException(e); |
| } |
| } |
| |
| public Serializable getId() { |
| return this.id; |
| } |
| |
| public void setId(Serializable id) { |
| this.id = id; |
| } |
| |
| public Date getStartTimestamp() { |
| return startTimestamp; |
| } |
| |
| public void setStartTimestamp(Date startTimestamp) { |
| this.startTimestamp = startTimestamp; |
| } |
| |
| /** |
| * Returns the time the session was stopped, or <tt>null</tt> if the session is still active. |
| * |
| * <p>A session may become stopped under a number of conditions: |
| * <ul> |
| * <li>If the user logs out of the system, their current session is terminated (released).</li> |
| * <li>If the session expires</li> |
| * <li>The application explicitly calls {@link #stop() destroy()}</li> |
| * <li>If there is an internal system error and the session state can no longer accurately |
| * reflect the user's behavior, such in the case of a system crash</li> |
| * </ul> |
| * </p> |
| * |
| * <p>Once stopped, a session may no longer be used. It is locked from all further activity. |
| * |
| * @return The time the session was stopped, or <tt>null</tt> if the session is still |
| * active. |
| */ |
| public Date getStopTimestamp() { |
| return stopTimestamp; |
| } |
| |
| public void setStopTimestamp(Date stopTimestamp) { |
| this.stopTimestamp = stopTimestamp; |
| } |
| |
| public Date getLastAccessTime() { |
| return lastAccessTime; |
| } |
| |
| public void setLastAccessTime(Date lastAccessTime) { |
| this.lastAccessTime = lastAccessTime; |
| } |
| |
| /** |
| * Returns true if this session has expired, false otherwise. If the session has |
| * expired, no further user interaction with the system may be done under this session. |
| * |
| * @return true if this session has expired, false otherwise. |
| */ |
| public boolean isExpired() { |
| return expired; |
| } |
| |
| public void setExpired(boolean expired) { |
| this.expired = expired; |
| } |
| |
| public long getTimeout() { |
| return timeout; |
| } |
| |
| public void setTimeout(long timeout) { |
| this.timeout = timeout; |
| } |
| |
| public InetAddress getHostAddress() { |
| return hostAddress; |
| } |
| |
| public void setHostAddress(InetAddress hostAddress) { |
| this.hostAddress = hostAddress; |
| } |
| |
| public Map<Object, Object> getAttributes() { |
| touch(); |
| return attributes; |
| } |
| |
| public void setAttributes(Map<Object, Object> attributes) { |
| touch(); |
| this.attributes = attributes; |
| } |
| |
| public void touch() { |
| this.lastAccessTime = new Date(); |
| } |
| |
| public void stop() { |
| if (this.stopTimestamp == null) { |
| this.stopTimestamp = new Date(); |
| } |
| } |
| |
| protected boolean isStopped() { |
| return getStopTimestamp() != null; |
| } |
| |
| protected void expire() { |
| stop(); |
| if ( !this.expired ) { |
| this.expired = true; |
| } |
| } |
| |
| /** |
| * @since 0.9 |
| */ |
| public boolean isValid() { |
| return !isStopped() && !isExpired(); |
| } |
| |
| /** |
| * Determines if this session is expired. |
| * |
| * @return true if the specified session has expired, false otherwise. |
| */ |
| protected boolean isTimedOut() { |
| |
| if (isExpired()) { |
| return true; |
| } |
| |
| long timeout = getTimeout(); |
| |
| if (timeout >= 0l) { |
| |
| Date lastAccessTime = getLastAccessTime(); |
| |
| if (lastAccessTime == null) { |
| String msg = "session.lastAccessTime for session with id [" + |
| getId() + "] is null. This value must be set at " + |
| "least once, preferably at least upon instantiation. Please check the " + |
| getClass().getName() + " implementation and ensure " + |
| "this value will be set (perhaps in the constructor?)"; |
| throw new IllegalStateException(msg); |
| } |
| |
| // Calculate at what time a session would have been last accessed |
| // for it to be expired at this point. In other words, subtract |
| // from the current time the amount of time that a session can |
| // be inactive before expiring. If the session was last accessed |
| // before this time, it is expired. |
| long expireTimeMillis = System.currentTimeMillis() - timeout; |
| Date expireTime = new Date(expireTimeMillis); |
| return lastAccessTime.before(expireTime); |
| } else { |
| if (log.isTraceEnabled()) { |
| log.trace("No timeout for session with id [" + getId() + |
| "]. Session is not considered expired."); |
| } |
| } |
| |
| return false; |
| } |
| |
| public void validate() throws InvalidSessionException { |
| //check for stopped: |
| if (isStopped()) { |
| //timestamp is set, so the session is considered stopped: |
| String msg = "Session with id [" + getId() + "] has been " + |
| "explicitly stopped. No further interaction under this session is " + |
| "allowed."; |
| throw new StoppedSessionException(msg, getId()); |
| } |
| |
| //check for expiration |
| if (isTimedOut()) { |
| expire(); |
| |
| //throw an exception explaining details of why it expired: |
| Date lastAccessTime = getLastAccessTime(); |
| long timeout = getTimeout(); |
| |
| Serializable sessionId = getId(); |
| |
| DateFormat df = DateFormat.getInstance(); |
| String msg = "Session with id [" + sessionId + "] has expired. " + |
| "Last access time: " + df.format(lastAccessTime) + |
| ". Current time: " + df.format(new Date()) + |
| ". Session timeout is set to " + timeout / MILLIS_PER_SECOND + " seconds (" + |
| timeout / MILLIS_PER_MINUTE + " minutes)"; |
| if (log.isTraceEnabled()) { |
| log.trace(msg); |
| } |
| throw new ExpiredSessionException(msg, sessionId); |
| } |
| } |
| |
| private Map<Object, Object> getAttributesLazy() { |
| Map<Object, Object> attributes = getAttributes(); |
| if (attributes == null) { |
| attributes = new HashMap<Object, Object>(); |
| setAttributes(attributes); |
| } |
| return attributes; |
| } |
| |
| public Collection<Object> getAttributeKeys() throws InvalidSessionException { |
| Map<Object, Object> attributes = getAttributes(); |
| if (attributes == null) { |
| //noinspection unchecked |
| return Collections.EMPTY_SET; |
| } |
| return attributes.keySet(); |
| } |
| |
| public Object getAttribute(Object key) { |
| Map<Object, Object> attributes = getAttributes(); |
| if (attributes == null) { |
| return null; |
| } |
| return attributes.get(key); |
| } |
| |
| public void setAttribute(Object key, Object value) { |
| if (value == null) { |
| removeAttribute(key); |
| } else { |
| getAttributesLazy().put(key, value); |
| } |
| } |
| |
| public Object removeAttribute(Object key) { |
| Map<Object, Object> attributes = getAttributes(); |
| if (attributes == null) { |
| return null; |
| } else { |
| return attributes.remove(key); |
| } |
| } |
| |
| } |