mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-04-24 08:57:16 +08:00
issue #69
抄了apache tomcat的源代码里关于Session, StandardSession, Manager, StandardManager中关于Session管理部分的代码。
This commit is contained in:
parent
8c80ca25b6
commit
1635024146
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 me.chanjar.weixin.common.session;
|
||||
|
||||
/**
|
||||
* Manifest constants for the <code>org.apache.catalina.session</code>
|
||||
* package.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String Package = "me.chanjar.weixin.common.session";
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package me.chanjar.weixin.common.session;
|
||||
|
||||
/**
|
||||
* Created by qianjia on 15/1/21.
|
||||
*/
|
||||
public interface InternalSession {
|
||||
|
||||
/**
|
||||
* Return the <code>HttpSession</code> for which this object
|
||||
* is the facade.
|
||||
*/
|
||||
WxSession getSession();
|
||||
|
||||
/**
|
||||
* Set the <code>isValid</code> flag for this session.
|
||||
*
|
||||
* @param isValid The new value for the <code>isValid</code> flag
|
||||
*/
|
||||
public void setValid(boolean isValid);
|
||||
|
||||
/**
|
||||
* Return the <code>isValid</code> flag for this session.
|
||||
*/
|
||||
boolean isValid();
|
||||
|
||||
/**
|
||||
* Return the session identifier for this session.
|
||||
*/
|
||||
String getIdInternal();
|
||||
|
||||
/**
|
||||
* Perform the internal processing required to invalidate this session,
|
||||
* without triggering an exception if the session has already expired.
|
||||
*/
|
||||
void expire();
|
||||
|
||||
/**
|
||||
* Update the accessed time information for this session. This method
|
||||
* should be called by the context when a request comes in for a particular
|
||||
* session, even if the application does not reference it.
|
||||
*/
|
||||
void access();
|
||||
|
||||
/**
|
||||
* Set the <code>isNew</code> flag for this session.
|
||||
*
|
||||
* @param isNew The new value for the <code>isNew</code> flag
|
||||
*/
|
||||
void setNew(boolean isNew);
|
||||
|
||||
/**
|
||||
* Set the creation time for this session. This method is called by the
|
||||
* Manager when an existing Session instance is reused.
|
||||
*
|
||||
* @param time The new creation time
|
||||
*/
|
||||
void setCreationTime(long time);
|
||||
|
||||
/**
|
||||
* Set the default maximum inactive interval (in seconds)
|
||||
* for Sessions created by this Manager.
|
||||
*
|
||||
* @param interval The new default value
|
||||
*/
|
||||
void setMaxInactiveInterval(int interval);
|
||||
|
||||
/**
|
||||
* Set the session identifier for this session.
|
||||
*
|
||||
* @param id The new session identifier
|
||||
*/
|
||||
void setId(String id);
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package me.chanjar.weixin.common.session;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Created by qianjia on 15/1/21.
|
||||
*/
|
||||
public class InternalSessionFacade implements WxSession {
|
||||
|
||||
/**
|
||||
* Wrapped session object.
|
||||
*/
|
||||
private WxSession session = null;
|
||||
|
||||
public InternalSessionFacade(WxSession session) {
|
||||
session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
return session.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
return session.getAttributeNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
session.setAttribute(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
session.removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
session.invalidate();
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package me.chanjar.weixin.common.session;
|
||||
|
||||
/**
|
||||
* Created by qianjia on 15/1/21.
|
||||
*/
|
||||
public interface InternalSessionManager {
|
||||
|
||||
/**
|
||||
* Construct and return a new session object, based on the default
|
||||
* settings specified by this Manager's properties. The session
|
||||
* id specified will be used as the session id.
|
||||
* If a new session cannot be created for any reason, return
|
||||
* <code>null</code>.
|
||||
*
|
||||
* @param sessionId The session id which should be used to create the
|
||||
* new session; if <code>null</code>, a new session id will be
|
||||
* generated
|
||||
* @exception IllegalStateException if a new session cannot be
|
||||
* instantiated for any reason
|
||||
*/
|
||||
public InternalSession createSession(String sessionId);
|
||||
|
||||
/**
|
||||
* Remove this Session from the active Sessions for this Manager.
|
||||
*
|
||||
* @param session Session to be removed
|
||||
*/
|
||||
public void remove(InternalSession session);
|
||||
|
||||
/**
|
||||
* Remove this Session from the active Sessions for this Manager.
|
||||
*
|
||||
* @param session Session to be removed
|
||||
* @param update Should the expiration statistics be updated
|
||||
*/
|
||||
public void remove(InternalSession session, boolean update);
|
||||
|
||||
/**
|
||||
* Add this Session to the set of active Sessions for this Manager.
|
||||
*
|
||||
* @param session Session to be added
|
||||
*/
|
||||
void add(InternalSession session);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of active sessions
|
||||
*
|
||||
* @return number of sessions active
|
||||
*/
|
||||
int getActiveSessions();
|
||||
/**
|
||||
* Get a session from the recycled ones or create a new empty one.
|
||||
* The PersistentManager manager does not need to create session data
|
||||
* because it reads it from the Store.
|
||||
*/
|
||||
InternalSession createEmptySession();
|
||||
|
||||
InternalSession[] findSessions();
|
||||
|
||||
/**
|
||||
* Implements the Manager interface, direct call to processExpires
|
||||
*/
|
||||
public void backgroundProcess();
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
# 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.
|
||||
|
||||
applicationSession.session.ise=invalid session state
|
||||
applicationSession.value.iae=null value
|
||||
fileStore.saving=Saving Session {0} to file {1}
|
||||
fileStore.loading=Loading Session {0} from file {1}
|
||||
fileStore.removing=Removing Session {0} at file {1}
|
||||
fileStore.deleteFailed=Unable to delete file [{0}] which is preventing the creation of the session storage location
|
||||
fileStore.createFailed=Unable to create directory [{0}] for the storage of session data
|
||||
JDBCStore.close=Exception closing database connection {0}
|
||||
JDBCStore.saving=Saving Session {0} to database {1}
|
||||
JDBCStore.loading=Loading Session {0} from database {1}
|
||||
JDBCStore.removing=Removing Session {0} at database {1}
|
||||
JDBCStore.SQLException=SQL Error {0}
|
||||
serverSession.value.iae=null value
|
||||
sessionManagerImpl.createRandom=Created random number generator for session ID generation in {0}ms.
|
||||
sessionManagerImpl.createSession.tmase=createSession: Too many active sessions
|
||||
sessionManagerImpl.sessionTimeout=Invalid session timeout setting {0}
|
||||
sessionManagerImpl.getSession.ise=getSession: Session id cannot be null
|
||||
sessionManagerImpl.expireException=processsExpire: Exception during session expiration
|
||||
sessionManagerImpl.loading=Loading persisted sessions from {0}
|
||||
sessionManagerImpl.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0}
|
||||
sessionManagerImpl.loading.ioe=IOException while loading persisted sessions: {0}
|
||||
sessionManagerImpl.unloading=Saving persisted sessions to {0}
|
||||
sessionManagerImpl.unloading.debug=Unloading persisted sessions
|
||||
sessionManagerImpl.unloading.ioe=IOException while saving persisted sessions: {0}
|
||||
sessionManagerImpl.unloading.nosessions=No persisted sessions to unload
|
||||
sessionManagerImpl.managerLoad=Exception loading sessions from persistent storage
|
||||
sessionManagerImpl.managerUnload=Exception unloading sessions to persistent storage
|
||||
sessionManagerImpl.createSession.ise=createSession: Session id cannot be null
|
||||
sessionImpl.attributeEvent=Session attribute event listener threw exception
|
||||
sessionImpl.bindingEvent=Session binding event listener threw exception
|
||||
sessionImpl.invalidate.ise=invalidate: Session already invalidated
|
||||
sessionImpl.isNew.ise=isNew: Session already invalidated
|
||||
sessionImpl.getAttribute.ise=getAttribute: Session already invalidated
|
||||
sessionImpl.getAttributeNames.ise=getAttributeNames: Session already invalidated
|
||||
sessionImpl.getCreationTime.ise=getCreationTime: Session already invalidated
|
||||
sessionImpl.getThisAccessedTime.ise=getThisAccessedTime: Session already invalidated
|
||||
sessionImpl.getLastAccessedTime.ise=getLastAccessedTime: Session already invalidated
|
||||
sessionImpl.getId.ise=getId: Session already invalidated
|
||||
sessionImpl.getMaxInactiveInterval.ise=getMaxInactiveInterval: Session already invalidated
|
||||
sessionImpl.getValueNames.ise=getValueNames: Session already invalidated
|
||||
sessionImpl.logoutfail=Exception logging out user when expiring session
|
||||
sessionImpl.notSerializable=Cannot serialize session attribute {0} for session {1}
|
||||
sessionImpl.removeAttribute.ise=removeAttribute: Session already invalidated
|
||||
sessionImpl.sessionEvent=Session event listener threw exception
|
||||
sessionImpl.setAttribute.iae=setAttribute: Non-serializable attribute {0}
|
||||
sessionImpl.setAttribute.ise=setAttribute: Session [{0}] has already been invalidated
|
||||
sessionImpl.setAttribute.namenull=setAttribute: name parameter cannot be null
|
||||
sessionImpl.sessionCreated=Created Session id = {0}
|
||||
persistentManager.loading=Loading {0} persisted sessions
|
||||
persistentManager.unloading=Saving {0} persisted sessions
|
||||
persistentManager.expiring=Expiring {0} sessions before saving them
|
||||
persistentManager.deserializeError=Error deserializing Session {0}: {1}
|
||||
persistentManager.serializeError=Error serializing Session {0}: {1}
|
||||
persistentManager.swapMaxIdle=Swapping session {0} to Store, idle for {1} seconds
|
||||
persistentManager.backupMaxIdle=Backing up session {0} to Store, idle for {1} seconds
|
||||
persistentManager.backupException=Exception occurred when backing up Session {0}: {1}
|
||||
persistentManager.tooManyActive=Too many active sessions, {0}, looking for idle sessions to swap out
|
||||
persistentManager.swapTooManyActive=Swapping out session {0}, idle for {1} seconds too many sessions active
|
||||
persistentManager.processSwaps=Checking for sessions to swap out, {0} active sessions in memory
|
||||
persistentManager.activeSession=Session {0} has been idle for {1} seconds
|
||||
persistentManager.swapIn=Swapping session {0} in from Store
|
||||
persistentManager.swapInException=Exception in the Store during swapIn: {0}
|
||||
persistentManager.swapInInvalid=Swapped session {0} is invalid
|
||||
persistentManager.storeKeysException=Unable to determine the list of session IDs for sessions in the session store, assuming that the store is empty
|
||||
persistentManager.storeSizeException=Unable to determine the number of sessions in the session store, assuming that the store is empty
|
@ -0,0 +1,294 @@
|
||||
package me.chanjar.weixin.common.session;
|
||||
|
||||
import me.chanjar.weixin.common.util.res.StringManager;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Created by qianjia on 15/1/21.
|
||||
*/
|
||||
public class SessionImpl 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;
|
||||
|
||||
/**
|
||||
* Flag indicating whether this session is new or not.
|
||||
*/
|
||||
protected boolean isNew = 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 last accessed time for this Session.
|
||||
*/
|
||||
protected volatile long lastAccessedTime = 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 InternalSessionFacade facade = null;
|
||||
|
||||
|
||||
public SessionImpl(InternalSessionManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WxSession getSession() {
|
||||
|
||||
if (facade == null){
|
||||
facade = new InternalSessionFacade(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() {
|
||||
return 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;
|
||||
|
||||
// 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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setNew(boolean isNew) {
|
||||
|
||||
this.isNew = isNew;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setCreationTime(long time) {
|
||||
|
||||
this.creationTime = time;
|
||||
this.lastAccessedTime = time;
|
||||
this.thisAccessedTime = time;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxInactiveInterval(int interval) {
|
||||
int oldMaxInactiveInterval = this.maxInactiveInterval;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
package me.chanjar.weixin.common.session;
|
||||
|
||||
import me.chanjar.weixin.common.util.res.StringManager;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SessionManagerImpl implements WxSessionManager, InternalSessionManager {
|
||||
|
||||
protected static final StringManager sm =
|
||||
StringManager.getManager(Constants.Package);
|
||||
|
||||
/**
|
||||
* The set of currently active Sessions for this Manager, keyed by
|
||||
* session identifier.
|
||||
*/
|
||||
protected Map<String, InternalSession> sessions = new ConcurrentHashMap<String, InternalSession>();
|
||||
|
||||
@Override
|
||||
public WxSession getSession(String sessionId) {
|
||||
return getSession(sessionId, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxSession getSession(String sessionId, boolean create) {
|
||||
if (sessionId == null) {
|
||||
throw new IllegalStateException
|
||||
(sm.getString("sessionManagerImpl.getSession.ise"));
|
||||
}
|
||||
|
||||
InternalSession session = findSession(sessionId);
|
||||
if ((session != null) && !session.isValid()) {
|
||||
session = null;
|
||||
}
|
||||
if (session != null) {
|
||||
session.access();
|
||||
return session.getSession();
|
||||
}
|
||||
|
||||
// Create a new session if requested and the response is not committed
|
||||
if (!create) {
|
||||
return (null);
|
||||
}
|
||||
|
||||
session = createSession(sessionId);
|
||||
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
session.access();
|
||||
return session.getSession();
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------- InternalSessionManager
|
||||
/**
|
||||
* The descriptive name of this Manager implementation (for logging).
|
||||
*/
|
||||
private static final String name = "SessionManagerImpl";
|
||||
|
||||
/**
|
||||
* The maximum number of active Sessions allowed, or -1 for no limit.
|
||||
*/
|
||||
protected int maxActiveSessions = -1;
|
||||
|
||||
/**
|
||||
* Number of session creations that failed due to maxActiveSessions.
|
||||
*/
|
||||
protected int rejectedSessions = 0;
|
||||
|
||||
/**
|
||||
* The default maximum inactive interval for Sessions created by
|
||||
* this Manager.
|
||||
*/
|
||||
protected int maxInactiveInterval = 30 * 60;
|
||||
|
||||
// Number of sessions created by this manager
|
||||
protected long sessionCounter=0;
|
||||
|
||||
protected volatile int maxActive=0;
|
||||
|
||||
private final Object maxActiveUpdateLock = new Object();
|
||||
|
||||
/**
|
||||
* Processing time during session expiration.
|
||||
*/
|
||||
protected long processingTime = 0;
|
||||
|
||||
/**
|
||||
* Iteration count for background processing.
|
||||
*/
|
||||
private int count = 0;
|
||||
|
||||
/**
|
||||
* Frequency of the session expiration, and related manager operations.
|
||||
* Manager operations will be done once for the specified amount of
|
||||
* backgrondProcess calls (ie, the lower the amount, the most often the
|
||||
* checks will occur).
|
||||
*/
|
||||
protected int processExpiresFrequency = 6;
|
||||
|
||||
@Override
|
||||
public void remove(InternalSession session) {
|
||||
remove(session, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(InternalSession session, boolean update) {
|
||||
if (session.getIdInternal() != null) {
|
||||
sessions.remove(session.getIdInternal());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the active Session, associated with this Manager, with the
|
||||
* specified session id (if any); otherwise return <code>null</code>.
|
||||
*
|
||||
* @param id The session id for the session to be returned
|
||||
*
|
||||
* @exception IllegalStateException if a new session cannot be
|
||||
* instantiated for any reason
|
||||
* @exception java.io.IOException if an input/output error occurs while
|
||||
* processing this request
|
||||
*/
|
||||
protected InternalSession findSession(String id) {
|
||||
|
||||
if (id == null)
|
||||
return (null);
|
||||
return sessions.get(id);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalSession createSession(String sessionId) {
|
||||
if (sessionId == null) {
|
||||
throw new IllegalStateException
|
||||
(sm.getString("sessionManagerImpl.createSession.ise"));
|
||||
}
|
||||
|
||||
if ((maxActiveSessions >= 0) &&
|
||||
(getActiveSessions() >= maxActiveSessions)) {
|
||||
rejectedSessions++;
|
||||
throw new TooManyActiveSessionsException(
|
||||
sm.getString("sessionManagerImpl.createSession.tmase"),
|
||||
maxActiveSessions);
|
||||
}
|
||||
|
||||
// Recycle or create a Session instance
|
||||
InternalSession session = createEmptySession();
|
||||
|
||||
// Initialize the properties of the new session and return it
|
||||
session.setNew(true);
|
||||
session.setValid(true);
|
||||
session.setCreationTime(System.currentTimeMillis());
|
||||
session.setMaxInactiveInterval(this.maxInactiveInterval);
|
||||
String id = sessionId;
|
||||
session.setId(id);
|
||||
sessionCounter++;
|
||||
|
||||
return (session);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getActiveSessions() {
|
||||
return sessions.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InternalSession createEmptySession() {
|
||||
return (getNewSession());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get new session class to be used in the doLoad() method.
|
||||
*/
|
||||
protected InternalSession getNewSession() {
|
||||
return new SessionImpl(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void add(InternalSession session) {
|
||||
|
||||
sessions.put(session.getIdInternal(), session);
|
||||
int size = getActiveSessions();
|
||||
if( size > maxActive ) {
|
||||
synchronized(maxActiveUpdateLock) {
|
||||
if( size > maxActive ) {
|
||||
maxActive = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of active Sessions associated with this Manager.
|
||||
* If this Manager has no active Sessions, a zero-length array is returned.
|
||||
*/
|
||||
@Override
|
||||
public InternalSession[] findSessions() {
|
||||
|
||||
return sessions.values().toArray(new InternalSession[0]);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void backgroundProcess() {
|
||||
count = (count + 1) % processExpiresFrequency;
|
||||
if (count == 0)
|
||||
processExpires();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all sessions that have expired.
|
||||
*/
|
||||
public void processExpires() {
|
||||
|
||||
long timeNow = System.currentTimeMillis();
|
||||
InternalSession sessions[] = findSessions();
|
||||
int expireHere = 0 ;
|
||||
|
||||
if(log.isDebugEnabled())
|
||||
log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
|
||||
for (int i = 0; i < sessions.length; i++) {
|
||||
if (sessions[i]!=null && !sessions[i].isValid()) {
|
||||
expireHere++;
|
||||
}
|
||||
}
|
||||
long timeEnd = System.currentTimeMillis();
|
||||
if(log.isDebugEnabled())
|
||||
log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
|
||||
processingTime += ( timeEnd - timeNow );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the descriptive short name of this Manager implementation.
|
||||
*/
|
||||
public String getName() {
|
||||
|
||||
return (name);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 me.chanjar.weixin.common.session;
|
||||
|
||||
/**
|
||||
* An exception that indicates the maximum number of active sessions has been
|
||||
* reached and the server is refusing to create any new sessions.
|
||||
*/
|
||||
public class TooManyActiveSessionsException
|
||||
extends IllegalStateException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The maximum number of active sessions the server will tolerate.
|
||||
*/
|
||||
private final int maxActiveSessions;
|
||||
|
||||
/**
|
||||
* Creates a new TooManyActiveSessionsException.
|
||||
*
|
||||
* @param message A description for the exception.
|
||||
* @param maxActive The maximum number of active sessions allowed by the
|
||||
* session manager.
|
||||
*/
|
||||
public TooManyActiveSessionsException(String message,
|
||||
int maxActive)
|
||||
{
|
||||
super(message);
|
||||
|
||||
maxActiveSessions = maxActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of sessions allowed by the session manager.
|
||||
*
|
||||
* @return The maximum number of sessions allowed by the session manager.
|
||||
*/
|
||||
public int getMaxActiveSessions()
|
||||
{
|
||||
return maxActiveSessions;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package me.chanjar.weixin.common.session;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Created by qianjia on 15/1/21.
|
||||
*/
|
||||
public interface WxSession {
|
||||
|
||||
public Object getAttribute(String name);
|
||||
|
||||
public Enumeration<String> getAttributeNames();
|
||||
|
||||
public void setAttribute(String name, Object value);
|
||||
|
||||
public void removeAttribute(String name);
|
||||
|
||||
public void invalidate();
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package me.chanjar.weixin.common.session;
|
||||
|
||||
public interface WxSessionManager {
|
||||
|
||||
|
||||
public WxSession getSession(String sessionId);
|
||||
|
||||
public WxSession getSession(String sessionId, boolean create);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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 me.chanjar.weixin.common.util.res;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* An internationalization / localization helper class which reduces
|
||||
* the bother of handling ResourceBundles and takes care of the
|
||||
* common cases of message formating which otherwise require the
|
||||
* creation of Object arrays and such.
|
||||
*
|
||||
* <p>The StringManager operates on a package basis. One StringManager
|
||||
* per package can be created and accessed via the getManager method
|
||||
* call.
|
||||
*
|
||||
* <p>The StringManager will look for a ResourceBundle named by
|
||||
* the package name given plus the suffix of "LocalStrings". In
|
||||
* practice, this means that the localized information will be contained
|
||||
* in a LocalStrings.properties file located in the package
|
||||
* directory of the classpath.
|
||||
*
|
||||
* <p>Please see the documentation for java.util.ResourceBundle for
|
||||
* more information.
|
||||
*
|
||||
* @author James Duncan Davidson [duncan@eng.sun.com]
|
||||
* @author James Todd [gonzo@eng.sun.com]
|
||||
* @author Mel Martinez [mmartinez@g1440.com]
|
||||
* @see java.util.ResourceBundle
|
||||
*/
|
||||
public class StringManager {
|
||||
|
||||
private static int LOCALE_CACHE_SIZE = 10;
|
||||
|
||||
/**
|
||||
* The ResourceBundle for this StringManager.
|
||||
*/
|
||||
private final ResourceBundle bundle;
|
||||
private final Locale locale;
|
||||
|
||||
/**
|
||||
* Creates a new StringManager for a given package. This is a
|
||||
* private method and all access to it is arbitrated by the
|
||||
* static getManager method call so that only one StringManager
|
||||
* per package will be created.
|
||||
*
|
||||
* @param packageName Name of package to create StringManager for.
|
||||
*/
|
||||
private StringManager(String packageName, Locale locale) {
|
||||
String bundleName = packageName + ".LocalStrings";
|
||||
ResourceBundle bnd = null;
|
||||
try {
|
||||
bnd = ResourceBundle.getBundle(bundleName, locale);
|
||||
} catch( MissingResourceException ex ) {
|
||||
// Try from the current loader (that's the case for trusted apps)
|
||||
// Should only be required if using a TC5 style classloader structure
|
||||
// where common != shared != server
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if( cl != null ) {
|
||||
try {
|
||||
bnd = ResourceBundle.getBundle(bundleName, locale, cl);
|
||||
} catch(MissingResourceException ex2) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
bundle = bnd;
|
||||
// Get the actual locale, which may be different from the requested one
|
||||
if (bundle != null) {
|
||||
Locale bundleLocale = bundle.getLocale();
|
||||
if (bundleLocale.equals(Locale.ROOT)) {
|
||||
this.locale = Locale.ENGLISH;
|
||||
} else {
|
||||
this.locale = bundleLocale;
|
||||
}
|
||||
} else {
|
||||
this.locale = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get a string from the underlying resource bundle or return
|
||||
null if the String is not found.
|
||||
|
||||
@param key to desired resource String
|
||||
@return resource String matching <i>key</i> from underlying
|
||||
bundle or null if not found.
|
||||
@throws IllegalArgumentException if <i>key</i> is null.
|
||||
*/
|
||||
public String getString(String key) {
|
||||
if(key == null){
|
||||
String msg = "key may not have a null value";
|
||||
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
String str = null;
|
||||
|
||||
try {
|
||||
// Avoid NPE if bundle is null and treat it like an MRE
|
||||
if (bundle != null) {
|
||||
str = bundle.getString(key);
|
||||
}
|
||||
} catch(MissingResourceException mre) {
|
||||
//bad: shouldn't mask an exception the following way:
|
||||
// str = "[cannot find message associated with key '" + key +
|
||||
// "' due to " + mre + "]";
|
||||
// because it hides the fact that the String was missing
|
||||
// from the calling code.
|
||||
//good: could just throw the exception (or wrap it in another)
|
||||
// but that would probably cause much havoc on existing
|
||||
// code.
|
||||
//better: consistent with container pattern to
|
||||
// simply return null. Calling code can then do
|
||||
// a null check.
|
||||
str = null;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string from the underlying resource bundle and format
|
||||
* it with the given set of arguments.
|
||||
*
|
||||
* @param key
|
||||
* @param args
|
||||
*/
|
||||
public String getString(final String key, final Object... args) {
|
||||
String value = getString(key);
|
||||
if (value == null) {
|
||||
value = key;
|
||||
}
|
||||
|
||||
MessageFormat mf = new MessageFormat(value);
|
||||
mf.setLocale(locale);
|
||||
return mf.format(args, new StringBuffer(), null).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify the Locale this StringManager is associated with
|
||||
*/
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// STATIC SUPPORT METHODS
|
||||
// --------------------------------------------------------------
|
||||
|
||||
private static final Map<String, Map<Locale,StringManager>> managers =
|
||||
new Hashtable<String, Map<Locale,StringManager>>();
|
||||
|
||||
/**
|
||||
* Get the StringManager for a particular package. If a manager for
|
||||
* a package already exists, it will be reused, else a new
|
||||
* StringManager will be created and returned.
|
||||
*
|
||||
* @param packageName The package name
|
||||
*/
|
||||
public static final synchronized StringManager getManager(
|
||||
String packageName) {
|
||||
return getManager(packageName, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the StringManager for a particular package and Locale. If a manager
|
||||
* for a package/Locale combination already exists, it will be reused, else
|
||||
* a new StringManager will be created and returned.
|
||||
*
|
||||
* @param packageName The package name
|
||||
* @param locale The Locale
|
||||
*/
|
||||
public static final synchronized StringManager getManager(
|
||||
String packageName, Locale locale) {
|
||||
|
||||
Map<Locale,StringManager> map = managers.get(packageName);
|
||||
if (map == null) {
|
||||
/*
|
||||
* Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE.
|
||||
* Expansion occurs when size() exceeds capacity. Therefore keep
|
||||
* size at or below capacity.
|
||||
* removeEldestEntry() executes after insertion therefore the test
|
||||
* for removal needs to use one less than the maximum desired size
|
||||
*
|
||||
*/
|
||||
map = new LinkedHashMap<Locale,StringManager>(LOCALE_CACHE_SIZE, 1, true) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
protected boolean removeEldestEntry(
|
||||
Map.Entry<Locale,StringManager> eldest) {
|
||||
if (size() > (LOCALE_CACHE_SIZE - 1)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
managers.put(packageName, map);
|
||||
}
|
||||
|
||||
StringManager mgr = map.get(locale);
|
||||
if (mgr == null) {
|
||||
mgr = new StringManager(packageName, locale);
|
||||
map.put(locale, mgr);
|
||||
}
|
||||
return mgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the StringManager for a list of Locales. The first StringManager
|
||||
* found will be returned.
|
||||
*
|
||||
* @param requestedLocales the list of Locales
|
||||
*
|
||||
* @return the found StringManager or the default StringManager
|
||||
*/
|
||||
public static StringManager getManager(String packageName,
|
||||
Enumeration<Locale> requestedLocales) {
|
||||
while (requestedLocales.hasMoreElements()) {
|
||||
Locale locale = requestedLocales.nextElement();
|
||||
StringManager result = getManager(packageName, locale);
|
||||
if (result.getLocale().equals(locale)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Return the default
|
||||
return getManager(packageName);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user