mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-09-24 04:53:50 +08:00
issue #69
抄了apache tomcat的源代码里关于Session, StandardSession, Manager, StandardManager中关于Session管理部分的代码。
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user