package me.chanjar.weixin.common.session; import me.chanjar.weixin.common.util.res.StringManager; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; public class StandardSession implements WxSession, InternalSession { /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------ WxSession protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>(); @Override public Object getAttribute(String name) { if (!isValidInternal()) throw new IllegalStateException (sm.getString("sessionImpl.getAttribute.ise")); if (name == null) return null; return (attributes.get(name)); } @Override public Enumeration<String> getAttributeNames() { if (!isValidInternal()) throw new IllegalStateException (sm.getString("sessionImpl.getAttributeNames.ise")); Set<String> names = new HashSet<String>(); names.addAll(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())); 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(); } // ------------------------------ InternalSession /** * 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; /** * Type array. */ protected static final String EMPTY_ARRAY[] = new String[0]; /** * 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 = 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 WxSession getSession() { if (facade == null){ facade = new StandardSessionFacade(this); } return (facade); } /** * Return the <code>isValid</code> flag for this session without any expiration * check. */ protected boolean isValidInternal() { return this.isValid; } /** * Set the <code>isValid</code> flag for this session. * * @param isValid The new value for the <code>isValid</code> flag */ @Override public void setValid(boolean isValid) { this.isValid = isValid; } @Override public boolean isValid() { if (!this.isValid) { return false; } if (this.expiring) { return true; } if (accessCount.get() > 0) { return true; } if (maxInactiveInterval > 0) { long timeNow = System.currentTimeMillis(); int timeIdle; timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L); if (timeIdle >= maxInactiveInterval) { expire(); } } return this.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 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 (!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 (expiring || !isValid) return; if (manager == null) return; // Mark this session as "being expired" expiring = true; accessCount.set(0); // Remove this session from our manager's active sessions manager.remove(this, true); // We have completed expire of this session setValid(false); expiring = false; // Unbind any objects associated with this session String keys[] = keys(); for (int i = 0; i < keys.length; i++) { removeAttributeInternal(keys[i]); } } } @Override public void access() { this.thisAccessedTime = System.currentTimeMillis(); accessCount.incrementAndGet(); } @Override public void endAccess() { this.thisAccessedTime = System.currentTimeMillis(); 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) && (manager != null)) manager.remove(this); this.id = id; if (manager != null) 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 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 (creationTime != session.creationTime) return false; if (expiring != session.expiring) return false; if (isValid != session.isValid) return false; if (maxInactiveInterval != session.maxInactiveInterval) return false; if (thisAccessedTime != session.thisAccessedTime) return false; if (!accessCount.equals(session.accessCount)) return false; if (!attributes.equals(session.attributes)) return false; if (!facade.equals(session.facade)) return false; if (!id.equals(session.id)) return false; if (!manager.equals(session.manager)) return false; return true; } @Override public int hashCode() { int result = attributes.hashCode(); result = 31 * result + id.hashCode(); result = 31 * result + (isValid ? 1 : 0); result = 31 * result + (expiring ? 1 : 0); result = 31 * result + manager.hashCode(); result = 31 * result + (int) (creationTime ^ (creationTime >>> 32)); result = 31 * result + (int) (thisAccessedTime ^ (thisAccessedTime >>> 32)); result = 31 * result + maxInactiveInterval; result = 31 * result + facade.hashCode(); result = 31 * result + accessCount.hashCode(); return result; } }