ソースを参照

issue #69

抄了apache tomcat的源代码里关于Session, StandardSession, Manager, StandardManager中关于Session管理部分的代码。
master
Daniel Qian 10年前
コミット
1635024146
11個のファイルの変更1178行の追加0行の削除
  1. +31
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/Constants.java
  2. +73
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java
  3. +43
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionFacade.java
  4. +66
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java
  5. +80
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/LocalStrings.properties
  6. +294
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/SessionImpl.java
  7. +252
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/SessionManagerImpl.java
  8. +57
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java
  9. +20
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java
  10. +11
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java
  11. +251
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java

+ 31
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/Constants.java ファイルの表示

@@ -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";

}

+ 73
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java ファイルの表示

@@ -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);
}

+ 43
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionFacade.java ファイルの表示

@@ -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();
}
}

+ 66
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java ファイルの表示

@@ -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();

}

+ 80
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/LocalStrings.properties ファイルの表示

@@ -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

+ 294
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/SessionImpl.java ファイルの表示

@@ -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);

}

}

+ 252
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/SessionManagerImpl.java ファイルの表示

@@ -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);

}

}

+ 57
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java ファイルの表示

@@ -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;
}
}

+ 20
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java ファイルの表示

@@ -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();

}

+ 11
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java ファイルの表示

@@ -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);


}

+ 251
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java ファイルの表示

@@ -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);
}
}

読み込み中…
キャンセル
保存