me.chanjar.weixin.common.session.StandardSession Maven / Gradle / Ivy
package me.chanjar.weixin.common.session;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import me.chanjar.weixin.common.util.res.StringManager;
/**
* @author Daniel Qian
*/
public class StandardSession implements WxSession, InternalSession {
/**
* The string manager for this package.
*/
protected static final StringManager SM = StringManager.getManager(Constants.PACKAGE);
/**
* Type array.
*/
private static final String[] EMPTY_ARRAY = new String[0];
protected Map attributes = new ConcurrentHashMap<>();
/**
* The session identifier of this Session.
*/
protected String id = null;
/**
* Flag indicating whether this session is valid or not.
*/
protected volatile boolean isValid = false;
/**
* We are currently processing a session expiration, so bypass
* certain IllegalStateException tests. NOTE: This value is not
* included in the serialized version of this object.
*/
protected transient volatile boolean expiring = false;
/**
* The Manager with which this Session is associated.
*/
protected transient InternalSessionManager manager = null;
// ------------------------------ InternalSession
/**
* The time this session was created, in milliseconds since midnight,
* January 1, 1970 GMT.
*/
protected long creationTime = 0L;
/**
* The current accessed time for this session.
*/
protected volatile long thisAccessedTime = this.creationTime;
/**
* The default maximum inactive interval for Sessions created by
* this Manager.
*/
protected int maxInactiveInterval = 30 * 60;
/**
* The facade associated with this session. NOTE: This value is not
* included in the serialized version of this object.
*/
protected transient StandardSessionFacade facade = null;
/**
* The access count for this session.
*/
protected transient AtomicInteger accessCount = null;
public StandardSession(InternalSessionManager manager) {
this.manager = manager;
this.accessCount = new AtomicInteger();
}
@Override
public Object getAttribute(String name) {
if (!isValidInternal()) {
throw new IllegalStateException
(SM.getString("sessionImpl.getAttribute.ise"));
}
if (name == null) {
return null;
}
return this.attributes.get(name);
}
@Override
public Enumeration getAttributeNames() {
if (!isValidInternal()) {
throw new IllegalStateException(SM.getString("sessionImpl.getAttributeNames.ise"));
}
Set names = new HashSet<>();
names.addAll(this.attributes.keySet());
return Collections.enumeration(names);
}
@Override
public void setAttribute(String name, Object value) {
// Name cannot be null
if (name == null) {
throw new IllegalArgumentException(SM.getString("sessionImpl.setAttribute.namenull"));
}
// Null value is the same as removeAttribute()
if (value == null) {
removeAttribute(name);
return;
}
// Validate our current state
if (!isValidInternal()) {
throw new IllegalStateException(SM.getString("sessionImpl.setAttribute.ise", getIdInternal()));
}
this.attributes.put(name, value);
}
@Override
public void removeAttribute(String name) {
removeAttributeInternal(name);
}
@Override
public void invalidate() {
if (!isValidInternal()) {
throw new IllegalStateException(SM.getString("sessionImpl.invalidate.ise"));
}
// Cause this session to expire
expire();
}
@Override
public WxSession getSession() {
if (this.facade == null) {
this.facade = new StandardSessionFacade(this);
}
return this.facade;
}
/**
* Return the isValid
flag for this session without any expiration
* check.
*/
protected boolean isValidInternal() {
return this.isValid;
}
@Override
public boolean isValid() {
if (!this.isValid) {
return false;
}
if (this.expiring) {
return true;
}
if (this.accessCount.get() > 0) {
return true;
}
if (this.maxInactiveInterval > 0) {
long timeNow = System.currentTimeMillis();
int timeIdle;
timeIdle = (int) ((timeNow - this.thisAccessedTime) / 1000L);
if (timeIdle >= this.maxInactiveInterval) {
expire();
}
}
return this.isValid;
}
/**
* Set the isValid
flag for this session.
*
* @param isValid The new value for the isValid
flag
*/
@Override
public void setValid(boolean isValid) {
this.isValid = isValid;
}
@Override
public String getIdInternal() {
return this.id;
}
protected void removeAttributeInternal(String name) {
// Avoid NPE
if (name == null) {
return;
}
// Remove this attribute from our collection
this.attributes.remove(name);
}
@Override
public void expire() {
// Check to see if session has already been invalidated.
// Do not check expiring at this point as expire should not return until
// isValid is false
if (!this.isValid) {
return;
}
synchronized (this) {
// Check again, now we are inside the sync so this code only runs once
// Double check locking - isValid needs to be volatile
// The check of expiring is to ensure that an infinite loop is not
// entered as per bug 56339
if (this.expiring || !this.isValid) {
return;
}
if (this.manager == null) {
return;
}
// Mark this session as "being expired"
this.expiring = true;
this.accessCount.set(0);
// Remove this session from our manager's active sessions
this.manager.remove(this, true);
// We have completed expire of this session
setValid(false);
this.expiring = false;
// Unbind any objects associated with this session
String[] keys = keys();
for (String key : keys) {
removeAttributeInternal(key);
}
}
}
@Override
public void access() {
this.thisAccessedTime = System.currentTimeMillis();
this.accessCount.incrementAndGet();
}
@Override
public void endAccess() {
this.thisAccessedTime = System.currentTimeMillis();
this.accessCount.decrementAndGet();
}
@Override
public void setCreationTime(long time) {
this.creationTime = time;
this.thisAccessedTime = time;
}
@Override
public void setMaxInactiveInterval(int interval) {
this.maxInactiveInterval = interval;
}
@Override
public void setId(String id) {
if ((this.id != null) && (this.manager != null)) {
this.manager.remove(this);
}
this.id = id;
if (this.manager != null) {
this.manager.add(this);
}
}
/**
* Return the names of all currently defined session attributes
* as an array of Strings. If there are no defined attributes, a
* zero-length array is returned.
*/
protected String[] keys() {
return this.attributes.keySet().toArray(EMPTY_ARRAY);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof StandardSession)) {
return false;
}
StandardSession session = (StandardSession) o;
if (this.creationTime != session.creationTime) {
return false;
}
if (this.expiring != session.expiring) {
return false;
}
if (this.isValid != session.isValid) {
return false;
}
if (this.maxInactiveInterval != session.maxInactiveInterval) {
return false;
}
if (this.thisAccessedTime != session.thisAccessedTime) {
return false;
}
if (this.accessCount.get() != session.accessCount.get()) {
return false;
}
if (!this.attributes.equals(session.attributes)) {
return false;
}
if (!this.facade.equals(session.facade)) {
return false;
}
return this.id.equals(session.id) && this.manager.equals(session.manager);
}
@Override
public int hashCode() {
int result = this.attributes.hashCode();
result = 31 * result + this.id.hashCode();
result = 31 * result + (this.isValid ? 1 : 0);
result = 31 * result + (this.expiring ? 1 : 0);
result = 31 * result + this.manager.hashCode();
result = 31 * result + (int) (this.creationTime ^ (this.creationTime >>> 32));
result = 31 * result + (int) (this.thisAccessedTime ^ (this.thisAccessedTime >>> 32));
result = 31 * result + this.maxInactiveInterval;
result = 31 * result + this.facade.hashCode();
result = 31 * result + this.accessCount.hashCode();
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy