com.caucho.server.session.SessionImpl Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.server.session;
import java.io.IOException;
import java.io.InputStream;
import java.io.NotSerializableException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import com.caucho.distcache.ByteStreamCache;
import com.caucho.distcache.ExtCacheEntry;
import com.caucho.json.Json;
import com.caucho.json.Transient;
import com.caucho.security.Login;
import com.caucho.server.util.CauchoSystem;
import com.caucho.server.webapp.WebApp;
import com.caucho.util.CacheListener;
import com.caucho.util.CurrentTime;
import com.caucho.util.L10N;
import com.caucho.vfs.IOExceptionWrapper;
import com.caucho.vfs.TempOutputStream;
/**
* Implements a HTTP session.
*/
public class SessionImpl implements HttpSession, CacheListener {
private static final Logger log
= Logger.getLogger(SessionImpl.class.getName());
private static final L10N L = new L10N(SessionImpl.class);
// the session's identifier
@Json(name = "SessionId")
private String _id;
// the owning session manager
@Transient
protected SessionManager _manager;
// the session objectStore
// Map containing the actual values.
@Transient
protected Map _values;
// time the session was created
@Json(name = "CreationTime")
private long _creationTime;
// time the session was last accessed
@Json(name = "AccessTime")
private long _accessTime;
// maximum time the session may stay alive.
@Json(name = "LastUseTime")
private long _lastUseTime;
@Json(name = "IdleTimeout")
private long _idleTimeout;
@Json(name = "IdleIsSet")
private boolean _isIdleSet;
// true if the session is new
@Json(name = "New")
private boolean _isNew = true;
// true if the application has modified the data
@Transient
private boolean _isModified;
// true if the session is still valid, i.e. not invalidated
@Json(name = "Valid")
private State _state = State.active;
// the cache entry saved in the session
@Transient
private ExtCacheEntry _cacheEntry;
// to protect for threading
@Json(name = "UseCount")
private final AtomicInteger _useCount = new AtomicInteger();
@Json(name = "LastSaveLength")
private int _lastSaveLength;
/**
* Create a new session object.
*
* @param manager the owning session manager.
* @param id the session identifier.
* @param creationTime the time in milliseconds when the session was created.
*/
public SessionImpl(SessionManager manager, String id, long creationTime)
{
_manager = manager;
// TCK requires exact time
creationTime = CurrentTime.getExactTime();
_creationTime = creationTime;
setAccessTime(creationTime);
_lastUseTime = _accessTime;
_idleTimeout = manager.getSessionTimeout();
_id = id;
_values = createValueMap();
if (log.isLoggable(Level.FINE))
log.fine(this + " new");
}
/**
* Create the map used to objectStore values.
*/
protected Map createValueMap()
{
return new TreeMap();
}
private boolean isClosed()
{
return _state.isClosed();
}
/**
* Returns the time the session was created.
*/
@Override
public long getCreationTime()
{
// this test forced by TCK
if (isClosed()) {
throw new IllegalStateException(L.l("{0}: can't call getCreationTime() when session is no longer valid.",
this));
}
return _creationTime;
}
/**
* Returns the session identifier.
*/
@Override
public String getId()
{
return _id;
}
/**
* Returns the last objectAccess time.
*/
@Override
public long getLastAccessedTime()
{
// this test forced by TCK
if (isClosed()) {
throw new IllegalStateException(L.l("{0}: can't call getLastAccessedTime() when session is no longer valid.",
this));
}
return _accessTime;
}
/**
* Returns the time the session is allowed to be alive.
*
* @return time allowed to live in seconds
*/
@Override
public int getMaxInactiveInterval()
{
if (Long.MAX_VALUE / 2 <= _idleTimeout)
return -1;
else
return (int) (_idleTimeout / 1000);
}
/**
* Sets the maximum time a session is allowed to be alive.
*
* @param value time allowed to live in seconds
*/
@Override
public void setMaxInactiveInterval(int value)
{
if (value < 0)
_idleTimeout = Long.MAX_VALUE / 2;
else
_idleTimeout = ((long) value) * 1000;
_isIdleSet = true;
}
/**
* Returns the session context.
*
* @deprecated
*/
public HttpSessionContext getSessionContext()
{
return null;
}
/**
* Returns the servlet context.
*/
public ServletContext getServletContext()
{
return _manager.getWebApp();
}
/**
* Returns the session manager.
*/
public SessionManager getManager()
{
return _manager;
}
/**
* Returns true if the session is new.
*/
public boolean isNew()
{
if (isClosed()) {
throw new IllegalStateException(L.l("{0} can't call isNew() when session is no longer valid.", this));
}
return _isNew;
}
/**
* Returns true if the session is valid.
*/
public boolean isValid()
{
return _state.isValid();
}
public boolean isTimeout()
{
return isTimeout(CurrentTime.getCurrentTime());
}
boolean isTimeout(long now)
{
long maxIdleTime = _idleTimeout;
if (isInUse()) {
return false;
}
else if (now < _lastUseTime + maxIdleTime) {
return false;
}
else {
long lastUseTime = getLastUseTime();
return lastUseTime + maxIdleTime < now;
}
}
private long getLastUseTime()
{
ByteStreamCache cache = _manager.getCache();
if (cache == null)
return _lastUseTime;
ExtCacheEntry entry = cache.peekExtCacheEntry(_id);
// server/01ke
if (entry == null)
return _lastUseTime;
else
return entry.getLastAccessedTime();
}
boolean isClosing()
{
return _state.isClosing();
}
/**
* Returns true if the session is empty.
*/
public boolean isEmpty()
{
return _values == null || _values.size() == 0;
}
/**
* Returns true if the session is in use.
*/
public boolean isInUse()
{
return _useCount.get() > 0;
}
protected int getUseCount()
{
return _useCount.get();
}
//
// Attribute API
//
/**
* Returns the named attribute from the session.
*/
@Override
public Object getAttribute(String name)
{
if (isClosed()) {
throw new IllegalStateException(L.l("{0}: can't call getAttribute() when session is no longer valid.",
this));
}
synchronized (_values) {
Object value = _values.get(name);
return value;
}
}
void setModified()
{
if (_values.size() > 0) {
_isModified = true;
}
}
/**
* Sets a session attribute. If the value is a listener, notify it
* of the objectModified. If the value has changed mark the session as changed
* for persistent sessions.
*
* @param name the name of the attribute
* @param value the value of the attribute
*/
@Override
public void setAttribute(String name, Object value)
{
if (isClosed()) {
throw new IllegalStateException(L.l("{0}: can't call setAttribute(String, Object) when session is no longer valid.", this));
}
Object oldValue;
if (value != null
&& ! (value instanceof Serializable)
&& log.isLoggable(Level.FINE)) {
log.fine(L.l("{0} attribute '{1}' value is non-serializable type '{2}'",
this, name, value.getClass().getName()));
}
synchronized (_values) {
if (value != null)
oldValue = _values.put(name, value);
else
oldValue = _values.remove(name);
}
// server/017p
_isModified = true;
if (oldValue instanceof HttpSessionBindingListener) {
HttpSessionBindingListener listener;
listener = (HttpSessionBindingListener) oldValue;
listener.valueUnbound(new HttpSessionBindingEvent(SessionImpl.this,
name, oldValue));
}
if (value instanceof HttpSessionBindingListener) {
HttpSessionBindingListener listener;
listener = (HttpSessionBindingListener) value;
listener.valueBound(new HttpSessionBindingEvent(SessionImpl.this,
name, value));
}
// Notify the attribute listeners
ArrayList listeners = _manager.getAttributeListeners();
if (listeners != null && listeners.size() > 0) {
HttpSessionBindingEvent event;
if (oldValue != null)
event = new HttpSessionBindingEvent(this, name, oldValue);
else
event = new HttpSessionBindingEvent(this, name, value);
for (int i = 0; i < listeners.size(); i++) {
HttpSessionAttributeListener listener;
listener = (HttpSessionAttributeListener) listeners.get(i);
if (oldValue != null)
listener.attributeReplaced(event);
else
listener.attributeAdded(event);
}
}
}
/**
* Remove a session attribute. If the value is a listener, notify it
* of the objectModified.
*
* @param name the name of the attribute to objectRemove
*/
public void removeAttribute(String name)
{
if (isClosed()) {
throw new IllegalStateException(L.l("{0}: can't call removeAttribute(String) when session is no longer valid.", this));
}
Object oldValue;
synchronized (_values) {
oldValue = _values.remove(name);
}
if (oldValue != null) {
_isModified = true;
}
notifyValueUnbound(name, oldValue);
}
/**
* Return an enumeration of all the sessions' attribute names.
*
* @return enumeration of the attribute names.
*/
public Enumeration getAttributeNames()
{
synchronized (_values) {
if (isClosed()) {
throw new IllegalStateException(L.l("{0} can't call getAttributeNames() when session is no longer valid.", this));
}
return Collections.enumeration(_values.keySet());
}
}
/**
* @deprecated
*/
public Object getValue(String name)
{
return getAttribute(name);
}
/**
* @deprecated
*/
public void putValue(String name, Object value)
{
setAttribute(name, value);
}
/**
* @deprecated
*/
public void removeValue(String name)
{
removeAttribute(name);
}
/**
* @deprecated
*/
public String []getValueNames()
{
synchronized (_values) {
if (isClosed()) {
throw new IllegalStateException(L.l("{0} can't call getValueNames() when session is no longer valid.", this));
}
if (_values == null)
return new String[0];
String []s = new String[_values.size()];
Enumeration e = getAttributeNames();
int count = 0;
while (e.hasMoreElements())
s[count++] = (String) e.nextElement();
return s;
}
}
//
// lifecycle: creation
//
/**
* Creates a new session.
*/
void create(long now, boolean isCreate)
{
if (log.isLoggable(Level.FINE)) {
log.fine(this + " create session");
}
// e.g. server 'C' when 'A' and 'B' have no record of session
if (! isClosed()) {
unbind();
}
// TCK now cares about exact time
now = CurrentTime.getExactTime();
// _isValid = true;
_isNew = true;
setAccessTime(now);
_creationTime = now;
// server/01np
_isModified = true;
/*
if (_clusterObject != null && isCreate)
_clusterObject.objectCreate();
*/
}
/**
* Set true if the session is in use.
*/
boolean addUse()
{
_lastUseTime = CurrentTime.getCurrentTime();
_useCount.incrementAndGet();
/*
synchronized (this) {
if (_isClosing)
return false;
_useCount++;
return true;
}
*/
return true;
}
/**
* Set true if the session is in use.
*/
void endUse()
{
_useCount.decrementAndGet();
/*
synchronized (this) {
_useCount--;
}
*/
}
/*
* Set the current objectAccess time to now.
*/
void setAccess(long now)
{
// server/01k0
if (_useCount.get() > 1)
return;
_isNew = false;
/*
if (_clusterObject != null)
_clusterObject.objectAccess();
*/
// TCK now cares about exact time
/*now = Alarm.getExactTime();
_accessTime = now;*/
}
public void setAccessTime(long accessTime)
{
// server/0123 (vs TCK?)
_accessTime = accessTime;
}
public int getLastSaveLength()
{
return _lastSaveLength;
}
/**
* Cleaning up session stuff at the end of a request.
*
* If the session data has changed and we have persistent sessions,
* save the session. However, if save-on-shutdown is true, only save
* on a server shutdown.
*/
public void finishRequest()
{
// server/0122
// TCK cares about exact time
setAccessTime(CurrentTime.getExactTime());
_isNew = false;
// update cache access?
if (_useCount.decrementAndGet() > 0)
return;
saveAfterRequest();
}
//
// persistent sessions and passivation
//
/**
* Loads the session.
*
* @return true if the session was found in the persistent store
*/
public boolean load(boolean isNew)
{
long now = CurrentTime.getCurrentTime();
if (! _state.isValid()) {
return false;
}
else if (_isIdleSet && _accessTime + _idleTimeout < now) {
// server/01o2 (tck)
return false;
}
// server/01k0
if (_useCount.get() > 1) {
return true;
}
try {
ByteStreamCache cache = _manager.getCache();
if (cache == null) {
return ! isNew;
}
// server/015m
if (! isNew && _manager.isSaveOnShutdown()) {
return true;
}
ExtCacheEntry entry = cache.getExtCacheEntry(_id);
ExtCacheEntry cacheEntry = _cacheEntry;
if (entry != null && ! entry.isValueNull()) {
// server/01a1, #4419
_idleTimeout = entry.getAccessedExpireTimeout();
long lastAccessTime = entry.getLastAccessedTime();
if (lastAccessTime + _idleTimeout * 5 / 4 < now) {
return false;
}
// _idleTimeout = entry.getIdleTimeout() * 4 / 5;
//_isIdleSet = true;
}
//if (entry != null && cacheEntry != null
// && cacheEntry.getValueHash() == entry.getValueHash()) {
if (entry != null && cacheEntry != null
&& (entry.getValueHash() == cacheEntry.getValueHash()
|| entry.getVersion() <= cacheEntry.getVersion())) {
if (log.isLoggable(Level.FINE)) {
log.fine(this + " session load-same valueHash="
+ (entry != null ? Long.toHexString(entry.getValueHash()) : null));
}
entry.updateAccessTime();
// #6289 _isModified = false;
return true;
}
TempOutputStream os = new TempOutputStream();
if (cache.get(_id, os)) {
InputStream is = os.getInputStream();
boolean isValid = false;
try {
HashChunkInputStream crcIs = new HashChunkInputStream(is);
SessionDeserializer in = _manager.createSessionDeserializer(crcIs);
if (log.isLoggable(Level.FINE)) {
log.fine(this + " session load valueHash="
+ (entry != null ? Long.toHexString(entry.getValueHash()) : null));
}
isValid = load(in);
in.close();
crcIs.close();
} finally {
is.close();
}
if (isValid) {
_cacheEntry = entry;
_isModified = false;
return true;
}
else {
_cacheEntry = entry;
_isModified = true;
return false;
}
}
else {
_cacheEntry = null;
if (log.isLoggable(Level.FINE)) {
log.fine(this + " session remove");
}
if (cacheEntry == null) {
return true;
}
}
} catch (IOException e) {
log.log(Level.WARNING, e.toString(), e);
}
return false;
}
/**
* Loads the object from the input stream.
*/
public boolean load(SessionDeserializer in)
throws IOException
{
HttpSessionEvent event = null;
ArrayList listeners = null;
String id = null;
synchronized (this) {
synchronized (_values) {
// server/017u
_values.clear();
// unbind();
try {
id = (String) in.readObject();
int size = in.readInt();
// System.out.println("LOAD: " + size + " " + this + " " + _clusterObject + System.identityHashCode(this));
for (int i = 0; i < size; i++) {
String key = (String) in.readObject();
Object value = in.readObject();
if (value != null) {
_values.put(key, value);
if (value instanceof HttpSessionActivationListener) {
HttpSessionActivationListener listener
= (HttpSessionActivationListener) value;
if (event == null)
event = new HttpSessionEvent(this);
if (listeners == null)
listeners = new ArrayList();
listeners.add(listener);
}
}
}
} catch (Exception e) {
log.log(Level.WARNING, e.toString(), e);
id = null;
}
}
}
for (int i = 0; listeners != null && i < listeners.size(); i++) {
HttpSessionActivationListener listener = listeners.get(i);
if (event == null)
event = new HttpSessionEvent(this);
listener.sessionDidActivate(event);
}
listeners = _manager.getActivationListeners();
for (int i = 0; listeners != null && i < listeners.size(); i++) {
HttpSessionActivationListener listener = listeners.get(i);
if (event == null)
event = new HttpSessionEvent(this);
listener.sessionDidActivate(event);
}
if (getId().equals(id)) {
return true;
}
else {
log.warning("Invalid session load id=" + getId() + ", but loaded id=" + id);
synchronized (_values) {
_values.clear();
}
return false;
}
}
/**
* Clears the session when reading a bad saved session.
*/
void reset(long now)
{
if (log.isLoggable(Level.FINER))
log.fine(this + " reset");
now = CurrentTime.getCurrentTime();
unbind();
//_isValid = true;
_isNew = true;
setAccessTime(now);
_creationTime = now;
}
/**
* Save changes before any flush.
*/
public final void saveBeforeFlush()
{
if (_manager == null || ! _manager.isSaveBeforeFlush()) {
return;
}
save();
}
/**
* Flush changes before the headers.
*/
public final void saveBeforeHeaders()
{
if (_manager == null || ! _manager.isSaveBeforeHeaders()) {
return;
}
save();
}
/**
* Flush changes after a request completes.
*/
public final void saveAfterRequest()
{
if (_manager == null || ! _manager.isSaveAfterRequest()) {
return;
}
save();
}
/**
* Saves changes to the session.
*/
public final void save()
{
if (! isValid()) {
return;
}
try {
if (! _isModified && ! _manager.getAlwaysSaveSession()) {
return;
}
if (! _manager.isPersistenceEnabled()) {
return;
}
_isModified = false;
TempOutputStream os = new TempOutputStream();
HashChunkOutputStream crcOs = new HashChunkOutputStream(os);
SessionSerializer out = _manager.createSessionSerializer(crcOs);
store(out);
out.close();
crcOs.close();
final int length = os.getLength();
_manager.addSessionSaveSample(length);
_lastSaveLength = length;
// #5170
long lastAccessTime = _accessTime;
long lastModifiedTime = lastAccessTime;
_cacheEntry = _manager.getCache().put(_id, os.getInputStream(),
_idleTimeout,
-1,
lastAccessTime,
lastModifiedTime);
if (log.isLoggable(Level.FINE)) {
log.fine(this + " session save valueHash="
+ (_cacheEntry != null ? Long.toHexString(_cacheEntry.getValueHash()) : null));
}
os.close();
} catch (Exception e) {
log.log(Level.WARNING, this + ": can't serialize session", e);
}
}
/**
* Store on shutdown.
*/
void saveOnShutdown()
{
/*
if (session.isValid()) {
synchronized (session) {
// server/016i, server/018x
if (! session.isEmpty())
session.saveOnShutdown();
}
}
*/
save();
/*
try {
ClusterObject clusterObject = _clusterObject;
if (clusterObject != null) {
clusterObject.objectModified();
clusterObject.objectStore(this);
}
} catch (Throwable e) {
log.log(Level.WARNING, this + ": can't serialize session", e);
}
*/
}
/**
* Passivates the session.
*/
public void passivate()
{
unbind();
}
/**
* Saves the object to the input stream.
*/
public void store(SessionSerializer out)
throws IOException
{
Set> set = null;
HttpSessionEvent event = null;
ArrayList listeners;
out.writeObject(getId());
synchronized (_values) {
set = _values.entrySet();
int size = set == null ? 0 : set.size();
if (size == 0) {
out.writeInt(0);
return;
}
listeners = _manager.getActivationListeners();
if (listeners != null && listeners.size() > 0) {
if (event == null)
event = new HttpSessionEvent(this);
for (int i = 0; i < listeners.size(); i++) {
HttpSessionActivationListener listener = listeners.get(i);
listener.sessionWillPassivate(event);
}
}
for (Map.Entry entry : set) {
Object value = entry.getValue();
if (value instanceof HttpSessionActivationListener) {
HttpSessionActivationListener listener
= (HttpSessionActivationListener) value;
if (event == null)
event = new HttpSessionEvent(this);
listener.sessionWillPassivate(event);
}
}
}
synchronized (this) {
synchronized (_values) {
set = _values.entrySet();
int size = set == null ? 0 : set.size();
out.writeInt(size);
if (size == 0) {
return;
}
boolean ignoreNonSerializable
= getManager().getIgnoreSerializationErrors();
for (Map.Entry entry : set) {
Object value = entry.getValue();
out.writeObject(entry.getKey());
if (ignoreNonSerializable && ! (value instanceof Serializable)) {
out.writeObject(null);
continue;
}
try {
out.writeObject(value);
} catch (NotSerializableException e) {
log.warning(L.l("{0}: failed storing persistent session attribute '{1}'. Persistent session values must extend java.io.Serializable.\n{2}",
this, entry.getKey(), String.valueOf(e)));
throw e;
}
}
}
}
}
//
// invalidation, lru, timeout
//
/**
* Invalidates the session, called by user code.
*
* This should never be called by Resin code (for logging purposes)
*/
public void invalidate()
{
if (log.isLoggable(Level.FINE))
log.fine(this + " invalidate");
_state = _state.toInvalidating();
invalidate(Logout.INVALIDATE);
}
/**
* Called by the session manager for a session timeout
*/
public void timeout()
{
// server/12i7
//if (! isValid())
// return;
if (! _manager.isPersistenceEnabled()) {
// if no persistent store then invalidate
// XXX: server/12cg - single signon shouldn't logout
invalidateTimeout();
}
/*
else if (session.getSrunIndex() != _selfIndex && _selfIndex >= 0) {
if (log.isLoggable(Level.FINE))
log.fine(session + " timeout (backup)");
// if not the owner, then just remove
_sessions.remove(session.getId());
}
*/
else {
invalidateTimeout();
}
}
/**
* Callback when the session is removed from the session cache, generally
* because the session cache is full.
*/
@Override
public void removeEvent()
{
synchronized (this) {
if (_state.isInvalidating() || _useCount.get() <= 0) {
_state = _state.toLru();
}
}
if (! _state.isClosing()) {
log.warning(L.l("{0} LRU while in use (use-count={1}). Consider increasing session-count.",
this,
_useCount));
}
if (log.isLoggable(Level.FINE)) {
log.fine(this + " remove " + _state);
}
long now = CurrentTime.getCurrentTime();
// server/015k, server/10g2
if (_state.isInvalidating()
|| _manager.isDestroyOnLru()
|| _accessTime + getMaxInactiveInterval() < now) {
notifyDestroy();
}
invalidateLocal();
// timeout();
}
private void notifyDestroy()
{
// server/01ni
/* XXX:
if (_clusterObject != null && ! _clusterObject.isPrimary())
return;
*/
ArrayList listeners = _manager.getListeners();
if (listeners != null) {
HttpSessionEvent event = new HttpSessionEvent(this);
for (int i = listeners.size() - 1; i >= 0; i--) {
HttpSessionListener listener;
listener = (HttpSessionListener) listeners.get(i);
listener.sessionDestroyed(event);
}
}
}
/**
* Invalidates a session based on a logout.
*/
public void invalidateLogout()
{
if (log.isLoggable(Level.FINE))
log.fine(this + " logout");
_state = _state.toInvalidating();
invalidate(Logout.INVALIDATE);
}
/**
* Invalidates a session based on a timeout
*/
void invalidateTimeout()
{
if (log.isLoggable(Level.FINE))
log.fine(this + " timeout");
if (_manager.isOwner(_id)) {
_state = _state.toInvalidating();
}
invalidate(Logout.TIMEOUT);
}
/**
* Invalidates a session based on a LRU
*/
void invalidateLru()
{
if (log.isLoggable(Level.FINE))
log.fine(this + " lru");
invalidateImpl(Logout.LRU);
}
/**
* Invalidates the session, called by user code.
*
* This should never be called by Resin code (for logging purposes)
*/
public void invalidateRemote()
{
if (log.isLoggable(Level.FINE))
log.fine(this + " invalidate remote");
_state = _state.toInvalidating();
invalidate(Logout.INVALIDATE);
}
/**
* Invalidates the session.
*/
private void invalidate(Logout logout)
{
if (isClosed()) {
throw new IllegalStateException(L.l("{0}: Can't call invalidate() when session is no longer valid.",
this));
}
try {
// server/017s
// server/12i1, 12ch
Login login = _manager.getWebApp().getLogin();
if (login != null) {
login.sessionInvalidate(this, logout == Logout.TIMEOUT);
}
_manager.removeSession(this);
invalidateImpl(logout);
} finally {
_state = _state.toClosed();
}
}
/**
* Invalidate the session, removing it from the manager,
* unbinding the values, and removing it from the objectStore.
*/
private void invalidateImpl(Logout logout)
{
State state = _state;
boolean invalidateAfterListener = _manager.isInvalidateAfterListener();
if (! invalidateAfterListener) {
_state = _state.toClosing();
}
try {
if (state.isInvalidating() && _manager.getSessionStore() != null) {
boolean isRemove = false;
// server/018z vs server/01ny
isRemove = true;
if (! isRemove && logout == Logout.TIMEOUT) {
// server/016r
ExtCacheEntry entry
= _manager.getSessionStore().peekExtCacheEntry(_id);
if (entry == null || ! entry.isValid()) {
isRemove = true;
}
}
else {
isRemove = true;
}
if (isRemove) {
_manager.getSessionStore().remove(_id);
}
}
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
invalidateLocal();
}
/**
* unbinds the session and saves if necessary.
*/
private void invalidateLocal()
{
if (! isClosed() && ! _state.isInvalidating()) {
if (_manager.isSaveOnlyOnShutdown()) {
save();
}
}
unbind(); // we're invalidating, not passivating
// server/12i7
Login login = _manager.getWebApp().getLogin();
if (login != null) {
login.sessionInvalidate(this, true);
}
}
/**
* Cleans up the session.
*/
public void unbind()
{
if (_values.size() == 0) {
return;
}
// ClusterObject clusterObject = _clusterObject;
ArrayList names = new ArrayList();
ArrayList