Prepare codebase to adhere to Checkstyle rules

Issue gh-393
This commit is contained in:
Vedran Pavic
2016-03-05 20:27:06 +01:00
committed by Rob Winch
parent 9e3bcafa75
commit 7f3302253b
222 changed files with 4071 additions and 3556 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session;
/**
* A {@link Session} that contains additional attributes that are useful for determining if a session is expired.
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
public interface ExpiringSession extends Session {
@@ -31,14 +32,14 @@ public interface ExpiringSession extends Session {
long getCreationTime();
/**
* Sets the last accessed time in milliseconds since midnight of 1/1/1970 GMT
* Sets the last accessed time in milliseconds since midnight of 1/1/1970 GMT.
*
* @param lastAccessedTime the last accessed time in milliseconds since midnight of 1/1/1970 GMT
*/
void setLastAccessedTime(long lastAccessedTime);
/**
* Gets the last time this {@link Session} was accessed expressed in milliseconds since midnight of 1/1/1970 GMT
* Gets the last time this {@link Session} was accessed expressed in milliseconds since midnight of 1/1/1970 GMT.
*
* @return the last time the client sent a request associated with the session expressed in milliseconds since midnight of 1/1/1970 GMT
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session;
import java.util.Map;
@@ -22,11 +23,10 @@ import java.util.Map;
* the principal name. The principal name is defined by the {@link Session}
* attribute with the name {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}.
*
* @author Rob Winch
*
* @param <S>
* the type of Session being managed by this
* {@link FindByIndexNameSessionRepository}
* @author Rob Winch
*/
public interface FindByIndexNameSessionRepository<S extends Session> extends SessionRepository<S> {
@@ -61,4 +61,4 @@ public interface FindByIndexNameSessionRepository<S extends Session> extends Ses
* an empty Map is returned.
*/
Map<String, S> findByIndexNameAndIndexValue(String indexName, String indexValue);
}
}

View File

@@ -1,18 +1,19 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session;
import java.io.Serializable;
@@ -37,22 +38,22 @@ import java.util.concurrent.TimeUnit;
* This implementation has no synchronization, so it is best to use the copy constructor when working on multiple threads.
* </p>
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
public final class MapSession implements ExpiringSession, Serializable {
/**
* Default {@link #setMaxInactiveIntervalInSeconds(int)} (30 minutes)
* Default {@link #setMaxInactiveIntervalInSeconds(int)} (30 minutes).
*/
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
private String id;
private Map<String, Object> sessionAttrs = new HashMap<String, Object>();
private long creationTime = System.currentTimeMillis();
private long lastAccessedTime = creationTime;
private long lastAccessedTime = this.creationTime;
/**
* Defaults to 30 minutes
* Defaults to 30 minutes.
*/
private int maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
@@ -75,12 +76,12 @@ public final class MapSession implements ExpiringSession, Serializable {
}
/**
* Creates a new instance from the provided {@link Session}
* Creates a new instance from the provided {@link Session}.
*
* @param session the {@link Session} to initialize this {@link Session} with. Cannot be null.
*/
public MapSession(ExpiringSession session) {
if(session == null) {
if (session == null) {
throw new IllegalArgumentException("session cannot be null");
}
this.id = session.getId();
@@ -99,15 +100,15 @@ public final class MapSession implements ExpiringSession, Serializable {
}
public long getCreationTime() {
return creationTime;
return this.creationTime;
}
public String getId() {
return id;
return this.id;
}
public long getLastAccessedTime() {
return lastAccessedTime;
return this.lastAccessedTime;
}
public void setMaxInactiveIntervalInSeconds(int interval) {
@@ -115,7 +116,7 @@ public final class MapSession implements ExpiringSession, Serializable {
}
public int getMaxInactiveIntervalInSeconds() {
return maxInactiveInterval;
return this.maxInactiveInterval;
}
public boolean isExpired() {
@@ -123,31 +124,32 @@ public final class MapSession implements ExpiringSession, Serializable {
}
boolean isExpired(long now) {
if(maxInactiveInterval < 0) {
if (this.maxInactiveInterval < 0) {
return false;
}
return now - TimeUnit.SECONDS.toMillis(maxInactiveInterval) >= lastAccessedTime;
return now - TimeUnit.SECONDS.toMillis(this.maxInactiveInterval) >= this.lastAccessedTime;
}
@SuppressWarnings("unchecked")
public <T> T getAttribute(String attributeName) {
return (T) sessionAttrs.get(attributeName);
return (T) this.sessionAttrs.get(attributeName);
}
public Set<String> getAttributeNames() {
return sessionAttrs.keySet();
return this.sessionAttrs.keySet();
}
public void setAttribute(String attributeName, Object attributeValue) {
if (attributeValue == null) {
removeAttribute(attributeName);
} else {
sessionAttrs.put(attributeName, attributeValue);
}
else {
this.sessionAttrs.put(attributeName, attributeValue);
}
}
public void removeAttribute(String attributeName) {
sessionAttrs.remove(attributeName);
this.sessionAttrs.remove(attributeName);
}
/**
@@ -168,12 +170,12 @@ public final class MapSession implements ExpiringSession, Serializable {
}
public boolean equals(Object obj) {
return obj instanceof Session && id.equals(((Session) obj).getId());
return obj instanceof Session && this.id.equals(((Session) obj).getId());
}
public int hashCode() {
return id.hashCode();
return this.id.hashCode();
}
private static final long serialVersionUID = 7160779239673823561L;
}
}

View File

@@ -1,26 +1,27 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
package org.springframework.session;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
/**
* A {@link SessionRepository} backed by a {@link java.util.Map} and that uses a {@link MapSession}. By default a
* {@link java.util.concurrent.ConcurrentHashMap} is used, but a custom {@link java.util.Map} can be injected to use
@@ -39,10 +40,10 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
*/
private Integer defaultMaxInactiveInterval;
private final Map<String,ExpiringSession> sessions;
private final Map<String, ExpiringSession> sessions;
/**
* Creates an instance backed by a {@link java.util.concurrent.ConcurrentHashMap}
* Creates an instance backed by a {@link java.util.concurrent.ConcurrentHashMap}.
*/
public MapSessionRepository() {
this(new ConcurrentHashMap<String, ExpiringSession>());
@@ -53,8 +54,8 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
*
* @param sessions the {@link java.util.Map} to use. Cannot be null.
*/
public MapSessionRepository(Map<String,ExpiringSession> sessions) {
if(sessions == null) {
public MapSessionRepository(Map<String, ExpiringSession> sessions) {
if (sessions == null) {
throw new IllegalArgumentException("sessions cannot be null");
}
this.sessions = sessions;
@@ -69,15 +70,15 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
}
public void save(ExpiringSession session) {
sessions.put(session.getId(), new MapSession(session));
this.sessions.put(session.getId(), new MapSession(session));
}
public ExpiringSession getSession(String id) {
ExpiringSession saved = sessions.get(id);
if(saved == null) {
ExpiringSession saved = this.sessions.get(id);
if (saved == null) {
return null;
}
if(saved.isExpired()) {
if (saved.isExpired()) {
delete(saved.getId());
return null;
}
@@ -85,13 +86,13 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
}
public void delete(String id) {
sessions.remove(id);
this.sessions.remove(id);
}
public ExpiringSession createSession() {
ExpiringSession result = new MapSession();
if(defaultMaxInactiveInterval != null) {
result.setMaxInactiveIntervalInSeconds(defaultMaxInactiveInterval);
if (this.defaultMaxInactiveInterval != null) {
result.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval);
}
return result;
}

View File

@@ -1,18 +1,19 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session;
import java.util.Set;
@@ -27,7 +28,7 @@ import java.util.Set;
public interface Session {
/**
* Gets a unique string that identifies the {@link Session}
* Gets a unique string that identifies the {@link Session}.
*
* @return a unique string that identifies the {@link Session}
*/
@@ -59,8 +60,8 @@ public interface Session {
void setAttribute(String attributeName, Object attributeValue);
/**
* Removes the attribute with the provided attribute name
* Removes the attribute with the provided attribute name.
* @param attributeName the name of the attribute to remove
*/
void removeAttribute(String attributeName);
}
}

View File

@@ -1,23 +1,25 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session;
/**
* A repository interface for managing {@link Session} instances.
*
* @param <S> the {@link Session} type
* @author Rob Winch
* @since 1.0
*/
@@ -59,4 +61,4 @@ public interface SessionRepository<S extends Session> {
* @param id the {@link org.springframework.session.Session#getId()} to delete
*/
void delete(String id);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.config.annotation.web.http;
import java.lang.annotation.Documented;
@@ -73,8 +74,8 @@ import org.springframework.session.events.SessionDestroyedEvent;
* @author Rob Winch
* @since 1.1
*/
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(SpringHttpSessionConfiguration.class)
@Configuration

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.config.annotation.web.http;
import java.util.ArrayList;
@@ -85,7 +86,7 @@ public class SpringHttpSessionConfiguration {
private CookieHttpSessionStrategy defaultHttpSessionStrategy = new CookieHttpSessionStrategy();
private HttpSessionStrategy httpSessionStrategy = defaultHttpSessionStrategy;
private HttpSessionStrategy httpSessionStrategy = this.defaultHttpSessionStrategy;
private List<HttpSessionListener> httpSessionListeners = new ArrayList<HttpSessionListener>();
@@ -93,22 +94,23 @@ public class SpringHttpSessionConfiguration {
@Bean
public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
return new SessionEventHttpSessionListenerAdapter(httpSessionListeners);
return new SessionEventHttpSessionListenerAdapter(this.httpSessionListeners);
}
@Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
sessionRepositoryFilter.setServletContext(servletContext);
if(httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy((MultiHttpSessionStrategy) httpSessionStrategy);
} else {
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy((MultiHttpSessionStrategy) this.httpSessionStrategy);
}
else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
}
return sessionRepositoryFilter;
}
@Autowired(required=false)
@Autowired(required = false)
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* 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,
@@ -33,8 +33,17 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.Delta;
import com.gemstone.gemfire.Instantiator;
import com.gemstone.gemfire.InvalidDeltaException;
import com.gemstone.gemfire.cache.EntryEvent;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
@@ -54,20 +63,12 @@ import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.Delta;
import com.gemstone.gemfire.Instantiator;
import com.gemstone.gemfire.InvalidDeltaException;
import com.gemstone.gemfire.cache.EntryEvent;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
/**
* AbstractGemFireOperationsSessionRepository is an abstract base class encapsulating functionality common
* to all implementations that support SessionRepository operations backed by GemFire.
*
* @author John Blum
* @since 1.1.0
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.context.ApplicationEventPublisher
* @see org.springframework.context.ApplicationEventPublisherAware
@@ -79,7 +80,6 @@ import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.util.CacheListenerAdapter
* @since 1.1.0
*/
public abstract class AbstractGemFireOperationsSessionRepository extends CacheListenerAdapter<Object, ExpiringSession>
implements InitializingBean, FindByIndexNameSessionRepository<ExpiringSession>,
@@ -140,7 +140,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* @see org.springframework.context.ApplicationEventPublisher
*/
protected ApplicationEventPublisher getApplicationEventPublisher() {
return applicationEventPublisher;
return this.applicationEventPublisher;
}
/**
@@ -150,7 +150,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* and manage Session data.
*/
protected String getFullyQualifiedRegionName() {
return fullyQualifiedRegionName;
return this.fullyQualifiedRegionName;
}
/**
@@ -170,7 +170,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* before it is considered expired.
*/
public int getMaxInactiveIntervalInSeconds() {
return maxInactiveIntervalInSeconds;
return this.maxInactiveIntervalInSeconds;
}
/**
@@ -181,7 +181,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* @see org.springframework.data.gemfire.GemfireOperations
*/
public GemfireOperations getTemplate() {
return template;
return this.template;
}
/**
@@ -198,7 +198,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
Region<Object, ExpiringSession> region = ((GemfireAccessor) template).getRegion();
fullyQualifiedRegionName = region.getFullPath();
this.fullyQualifiedRegionName = region.getFullPath();
region.getAttributesMutator().addCacheListener(this);
}
@@ -318,7 +318,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
getApplicationEventPublisher().publishEvent(event);
}
catch (Throwable t) {
logger.error(String.format("error occurred publishing event (%1$s)", event), t);
this.logger.error(String.format("error occurred publishing event (%1$s)", event), t);
}
}
@@ -346,7 +346,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
static {
Instantiator.register(new Instantiator(GemFireSession.class, 800813552) {
@Override public DataSerializable newInstance() {
@Override
public DataSerializable newInstance() {
return new GemFireSession();
}
});
@@ -415,37 +416,37 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public synchronized String getId() {
return id;
return this.id;
}
/* (non-Javadoc) */
public synchronized long getCreationTime() {
return creationTime;
return this.creationTime;
}
/* (non-Javadoc) */
public void setAttribute(String attributeName, Object attributeValue) {
sessionAttributes.setAttribute(attributeName, attributeValue);
this.sessionAttributes.setAttribute(attributeName, attributeValue);
}
/* (non-Javadoc) */
public void removeAttribute(String attributeName) {
sessionAttributes.removeAttribute(attributeName);
this.sessionAttributes.removeAttribute(attributeName);
}
/* (non-Javadoc) */
public <T> T getAttribute(String attributeName) {
return sessionAttributes.getAttribute(attributeName);
return this.sessionAttributes.getAttribute(attributeName);
}
/* (non-Javadoc) */
public Set<String> getAttributeNames() {
return sessionAttributes.getAttributeNames();
return this.sessionAttributes.getAttributeNames();
}
/* (non-Javadoc) */
public GemFireSessionAttributes getAttributes() {
return sessionAttributes;
return this.sessionAttributes;
}
/* (non-Javadoc) */
@@ -470,7 +471,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public synchronized long getLastAccessedTime() {
return lastAccessedTime;
return this.lastAccessedTime;
}
/* (non-Javadoc) */
@@ -481,7 +482,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public synchronized int getMaxInactiveIntervalInSeconds() {
return maxInactiveIntervalInSeconds;
return this.maxInactiveIntervalInSeconds;
}
/* (non-Javadoc) */
@@ -497,7 +498,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
Object authentication = getAttribute(SPRING_SECURITY_CONTEXT);
if (authentication != null) {
Expression expression = parser.parseExpression("authentication?.name");
Expression expression = this.parser.parseExpression("authentication?.name");
principalName = expression.getValue(authentication, String.class);
}
}
@@ -521,7 +522,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
out.writeUTF(principalName);
}
writeObject(sessionAttributes, out);
writeObject(this.sessionAttributes, out);
this.delta = false;
}
@@ -533,8 +534,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public synchronized void fromData(DataInput in) throws ClassNotFoundException, IOException {
id = in.readUTF();
creationTime = in.readLong();
this.id = in.readUTF();
this.creationTime = in.readLong();
setLastAccessedTime(in.readLong());
setMaxInactiveIntervalInSeconds(in.readInt());
@@ -544,7 +545,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
setPrincipalName(in.readUTF());
}
sessionAttributes.from(this.<GemFireSessionAttributes>readObject(in));
this.sessionAttributes.from(this.<GemFireSessionAttributes>readObject(in));
this.delta = false;
}
@@ -556,14 +557,14 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public synchronized boolean hasDelta() {
return (delta || sessionAttributes.hasDelta());
return (this.delta || this.sessionAttributes.hasDelta());
}
/* (non-Javadoc) */
public synchronized void toDelta(DataOutput out) throws IOException {
out.writeLong(getLastAccessedTime());
out.writeInt(getMaxInactiveIntervalInSeconds());
sessionAttributes.toDelta(out);
this.sessionAttributes.toDelta(out);
this.delta = false;
}
@@ -571,7 +572,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
public synchronized void fromDelta(DataInput in) throws IOException {
setLastAccessedTime(in.readLong());
setMaxInactiveIntervalInSeconds(in.readInt());
sessionAttributes.fromDelta(in);
this.sessionAttributes.fromDelta(in);
this.delta = false;
}
@@ -640,7 +641,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
static {
Instantiator.register(new Instantiator(GemFireSessionAttributes.class, 800828008) {
@Override public DataSerializable newInstance() {
@Override
public DataSerializable newInstance() {
return new GemFireSessionAttributes();
}
});
@@ -663,10 +665,10 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public void setAttribute(String attributeName, Object attributeValue) {
synchronized (lock) {
synchronized (this.lock) {
if (attributeValue != null) {
if (!attributeValue.equals(sessionAttributes.put(attributeName, attributeValue))) {
sessionAttributeDeltas.put(attributeName, attributeValue);
if (!attributeValue.equals(this.sessionAttributes.put(attributeName, attributeValue))) {
this.sessionAttributeDeltas.put(attributeName, attributeValue);
}
}
else {
@@ -677,9 +679,9 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public void removeAttribute(String attributeName) {
synchronized (lock) {
if (sessionAttributes.remove(attributeName) != null) {
sessionAttributeDeltas.put(attributeName, null);
synchronized (this.lock) {
if (this.sessionAttributes.remove(attributeName) != null) {
this.sessionAttributeDeltas.put(attributeName, null);
}
}
}
@@ -687,15 +689,15 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
public <T> T getAttribute(String attributeName) {
synchronized (lock) {
return (T) sessionAttributes.get(attributeName);
synchronized (this.lock) {
return (T) this.sessionAttributes.get(attributeName);
}
}
/* (non-Javadoc) */
public Set<String> getAttributeNames() {
synchronized (lock) {
return Collections.unmodifiableSet(new HashSet<String>(sessionAttributes.keySet()));
synchronized (this.lock) {
return Collections.unmodifiableSet(new HashSet<String>(this.sessionAttributes.keySet()));
}
}
@@ -709,19 +711,21 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
@SuppressWarnings("all")
public Set<Entry<String, Object>> entrySet() {
return new AbstractSet<Entry<String, Object>>() {
@Override public Iterator<Entry<String, Object>> iterator() {
return Collections.unmodifiableMap(sessionAttributes).entrySet().iterator();
@Override
public Iterator<Entry<String, Object>> iterator() {
return Collections.unmodifiableMap(GemFireSessionAttributes.this.sessionAttributes).entrySet().iterator();
}
@Override public int size() {
return sessionAttributes.size();
@Override
public int size() {
return GemFireSessionAttributes.this.sessionAttributes.size();
}
};
}
/* (non-Javadoc) */
public void from(Session session) {
synchronized (lock) {
synchronized (this.lock) {
for (String attributeName : session.getAttributeNames()) {
setAttribute(attributeName, session.getAttribute(attributeName));
}
@@ -730,7 +734,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public void from(GemFireSessionAttributes sessionAttributes) {
synchronized (lock) {
synchronized (this.lock) {
for (String attributeName : sessionAttributes.getAttributeNames()) {
setAttribute(attributeName, sessionAttributes.getAttribute(attributeName));
}
@@ -739,7 +743,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public void toData(DataOutput out) throws IOException {
synchronized (lock) {
synchronized (this.lock) {
Set<String> attributeNames = getAttributeNames();
out.writeInt(attributeNames.size());
@@ -758,44 +762,44 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
synchronized (lock) {
synchronized (this.lock) {
for (int count = in.readInt(); count > 0; count--) {
setAttribute(in.readUTF(), readObject(in));
}
sessionAttributeDeltas.clear();
this.sessionAttributeDeltas.clear();
}
}
/* (non-Javadoc) */
<T> T readObject(DataInput in) throws ClassNotFoundException , IOException {
<T> T readObject(DataInput in) throws ClassNotFoundException, IOException {
return DataSerializer.readObject(in);
}
/* (non-Javadoc) */
public boolean hasDelta() {
synchronized (lock) {
return !sessionAttributeDeltas.isEmpty();
synchronized (this.lock) {
return !this.sessionAttributeDeltas.isEmpty();
}
}
/* (non-Javadoc) */
public void toDelta(DataOutput out) throws IOException {
synchronized (lock) {
out.writeInt(sessionAttributeDeltas.size());
synchronized (this.lock) {
out.writeInt(this.sessionAttributeDeltas.size());
for (Map.Entry<String, Object> entry : sessionAttributeDeltas.entrySet()) {
for (Map.Entry<String, Object> entry : this.sessionAttributeDeltas.entrySet()) {
out.writeUTF(entry.getKey());
writeObject(entry.getValue(), out);
}
sessionAttributeDeltas.clear();
this.sessionAttributeDeltas.clear();
}
}
/* (non-Javadoc) */
public void fromDelta(DataInput in) throws InvalidDeltaException, IOException {
synchronized (lock) {
synchronized (this.lock) {
try {
int count = in.readInt();
@@ -807,7 +811,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
for (Map.Entry<String, Object> entry : deltas.entrySet()) {
setAttribute(entry.getKey(), entry.getValue());
sessionAttributeDeltas.remove(entry.getKey());
this.sessionAttributeDeltas.remove(entry.getKey());
}
}
catch (ClassNotFoundException e) {
@@ -818,7 +822,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
@Override
public String toString() {
return sessionAttributes.toString();
return this.sessionAttributes.toString();
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* 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,
@@ -19,21 +19,21 @@ package org.springframework.session.data.gemfire;
import java.util.HashMap;
import java.util.Map;
import com.gemstone.gemfire.cache.query.SelectResults;
import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.session.ExpiringSession;
import com.gemstone.gemfire.cache.query.SelectResults;
/**
* The GemFireOperationsSessionRepository class is a Spring SessionRepository implementation that interfaces with
* and uses GemFire to back and store Spring Sessions.
*
* @author John Blum
* @since 1.1.0
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository
* @since 1.1.0
*/
public class GemFireOperationsSessionRepository extends AbstractGemFireOperationsSessionRepository {

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* 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,
@@ -22,12 +22,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Add this annotation to an {@code @Configuration} class to expose the SessionRepositoryFilter
* as a bean named "springSessionRepositoryFilter" and backed by Pivotal GemFire or Apache Geode.

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* 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,
@@ -18,6 +18,14 @@ package org.springframework.session.data.gemfire.config.annotation.web.http;
import java.util.concurrent.TimeUnit;
import com.gemstone.gemfire.cache.ExpirationAction;
import com.gemstone.gemfire.cache.ExpirationAttributes;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
@@ -40,19 +48,12 @@ import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.cache.ExpirationAction;
import com.gemstone.gemfire.cache.ExpirationAttributes;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
/**
* The GemFireHttpSessionConfiguration class is a Spring @Configuration class used to configure and initialize
* Pivotal GemFire (or Apache Geode) as a clustered, replicated HttpSession provider implementation in Spring Session.
*
* @author John Blum
* @since 1.1.0
* @see org.springframework.beans.factory.BeanClassLoaderAware
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
@@ -71,23 +72,40 @@ import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
* @see com.gemstone.gemfire.cache.RegionAttributes
* @see com.gemstone.gemfire.cache.RegionShortcut
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
* @since 1.1.0
*/
@Configuration
public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements BeanClassLoaderAware, ImportAware {
/**
* The default maximum interval in seconds in which a Session can remain inactive
* before it is considered expired.
*/
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS = (int) TimeUnit.MINUTES.toSeconds(30);
protected static final Class<Object> SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT = Object.class;
protected static final Class<GemFireSession> SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT = GemFireSession.class;
/**
* The default {@link ClientRegionShortcut} used to configure the GemFire ClientCache
* Region that will store Spring Sessions.
*/
public static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = ClientRegionShortcut.PROXY;
/**
* The default {@link RegionShortcut} used to configure the GemFire Cache Region that
* will store Spring Sessions.
*/
public static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = RegionShortcut.PARTITION;
/**
* The default name of the Gemfire (Client)Cache Region used to store Sessions.
*/
public static final String DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME = "ClusteredSpringSessions";
/**
* The default names of all Session attributes that should be indexed by GemFire.
*/
public static final String[] DEFAULT_INDEXABLE_SESSION_ATTRIBUTES = new String[0];
private int maxInactiveIntervalInSeconds = DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
@@ -120,7 +138,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see java.lang.ClassLoader
*/
protected ClassLoader getBeanClassLoader() {
return beanClassLoader;
return this.beanClassLoader;
}
/**
@@ -143,7 +161,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see EnableGemFireHttpSession#clientRegionShortcut()
*/
protected ClientRegionShortcut getClientRegionShortcut() {
return (clientRegionShortcut != null ? clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT);
return (this.clientRegionShortcut != null ? this.clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT);
}
/**
@@ -164,7 +182,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see EnableGemFireHttpSession#indexableSessionAttributes()
*/
protected String[] getIndexableSessionAttributes() {
return (indexableSessionAttributes != null ? indexableSessionAttributes : DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
return (this.indexableSessionAttributes != null ? this.indexableSessionAttributes : DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
}
/**
@@ -207,7 +225,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see EnableGemFireHttpSession#maxInactiveIntervalInSeconds()
*/
protected int getMaxInactiveIntervalInSeconds() {
return maxInactiveIntervalInSeconds;
return this.maxInactiveIntervalInSeconds;
}
/**
@@ -217,7 +235,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see com.gemstone.gemfire.cache.RegionShortcut
*/
public void setServerRegionShortcut(RegionShortcut shortcut) {
serverRegionShortcut = shortcut;
this.serverRegionShortcut = shortcut;
}
/**
@@ -229,7 +247,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see EnableGemFireHttpSession#serverRegionShortcut()
*/
protected RegionShortcut getServerRegionShortcut() {
return (serverRegionShortcut != null ? serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT);
return (this.serverRegionShortcut != null ? this.serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT);
}
/**
@@ -251,7 +269,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see EnableGemFireHttpSession#regionName()
*/
protected String getSpringSessionGemFireRegionName() {
return (StringUtils.hasText(springSessionGemFireRegionName) ? springSessionGemFireRegionName
return (StringUtils.hasText(this.springSessionGemFireRegionName) ? this.springSessionGemFireRegionName
: DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
}
@@ -408,7 +426,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
@DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public IndexFactoryBean principalNameIndex(final GemFireCache gemfireCache) {
IndexFactoryBean index = new IndexFactoryBean() {
@Override public void afterPropertiesSet() throws Exception {
@Override
public void afterPropertiesSet() throws Exception {
if (GemFireUtils.isPeer(gemfireCache)) {
super.afterPropertiesSet();
}
@@ -439,7 +458,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
@DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public IndexFactoryBean sessionAttributesIndex(final GemFireCache gemfireCache) {
IndexFactoryBean index = new IndexFactoryBean() {
@Override public void afterPropertiesSet() throws Exception {
@Override
public void afterPropertiesSet() throws Exception {
if (GemFireUtils.isPeer(gemfireCache) && !ObjectUtils.isEmpty(getIndexableSessionAttributes())) {
super.afterPropertiesSet();
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* 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,
@@ -16,6 +16,13 @@
package org.springframework.session.data.gemfire.config.annotation.web.http.support;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.InterestResultPolicy;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.GenericRegionFactoryBean;
@@ -26,18 +33,14 @@ import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.InterestResultPolicy;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
/**
* The GemFireCacheTypeAwareRegionFactoryBean class is a Spring {@link FactoryBean} used to construct, configure
* and initialize the GemFire cache {@link Region} used to store and manage Session state.
*
* @param <K> the type of keys
* @param <V> the type of values
* @author John Blum
* @since 1.1.0
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.GenericRegionFactoryBean
@@ -49,7 +52,6 @@ import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
* @see com.gemstone.gemfire.cache.RegionAttributes
* @see com.gemstone.gemfire.cache.RegionShortcut
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
* @since 1.1.0
*/
public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean<Region<K, V>>, InitializingBean {
@@ -88,7 +90,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
public void afterPropertiesSet() throws Exception {
GemFireCache gemfireCache = getGemfireCache();
region = (GemFireUtils.isClient(gemfireCache) ? newClientRegion(gemfireCache)
this.region = (GemFireUtils.isClient(gemfireCache) ? newClientRegion(gemfireCache)
: newServerRegion(gemfireCache));
}
@@ -179,7 +181,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
* @see com.gemstone.gemfire.cache.Region
*/
public Region<K, V> getObject() throws Exception {
return region;
return this.region;
}
/**
@@ -191,7 +193,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
* @see java.lang.Class
*/
public Class<?> getObjectType() {
return (region != null ? region.getClass() : Region.class);
return (this.region != null ? this.region.getClass() : Region.class);
}
/**
@@ -223,7 +225,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/
protected ClientRegionShortcut getClientRegionShortcut() {
return (clientRegionShortcut != null ? clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT);
return (this.clientRegionShortcut != null ? this.clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT);
}
/**
@@ -244,8 +246,8 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
* @throws IllegalStateException if the {@link GemFireCache} reference is null.
*/
protected GemFireCache getGemfireCache() {
Assert.state(gemfireCache != null, "A reference to a GemFireCache was not properly configured");
return gemfireCache;
Assert.state(this.gemfireCache != null, "A reference to a GemFireCache was not properly configured");
return this.gemfireCache;
}
/**
@@ -267,7 +269,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
* @see com.gemstone.gemfire.cache.RegionAttributes
*/
protected RegionAttributes<K, V> getRegionAttributes() {
return regionAttributes;
return this.regionAttributes;
}
/**
@@ -287,7 +289,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
* @see com.gemstone.gemfire.cache.Region#getName()
*/
protected String getRegionName() {
return (StringUtils.hasText(regionName) ? regionName : DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
return (StringUtils.hasText(this.regionName) ? this.regionName : DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
}
/**
@@ -308,7 +310,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
* @see com.gemstone.gemfire.cache.RegionShortcut
*/
protected RegionShortcut getServerRegionShortcut() {
return (serverRegionShortcut != null ? serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT);
return (this.serverRegionShortcut != null ? this.serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT);
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* 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,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.redis;
import org.springframework.session.SessionRepository;

View File

@@ -1,18 +1,19 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session.data.redis;
import java.util.Collections;
@@ -23,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.connection.Message;
@@ -245,9 +247,8 @@ import org.springframework.util.Assert;
* if the TTL on that key is expired.
* </p>
*
* @since 1.0
*
* @author Rob Winch
* @since 1.0
*/
public class RedisOperationsSessionRepository implements FindByIndexNameSessionRepository<RedisOperationsSessionRepository.RedisSession>, MessageListener {
private static final Log logger = LogFactory.getLog(RedisOperationsSessionRepository.class);
@@ -257,22 +258,22 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
static PrincipalNameResolver PRINCIPAL_NAME_RESOLVER = new PrincipalNameResolver();
/**
* The default prefix for each key and channel in Redis used by Spring Session
* The default prefix for each key and channel in Redis used by Spring Session.
*/
static final String DEFAULT_SPRING_SESSION_REDIS_PREFIX = "spring:session:";
/**
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getCreationTime()}
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getCreationTime()}.
*/
static final String CREATION_TIME_ATTR = "creationTime";
/**
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getMaxInactiveIntervalInSeconds()}
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getMaxInactiveIntervalInSeconds()}.
*/
static final String MAX_INACTIVE_ATTR = "maxInactiveInterval";
/**
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getLastAccessedTime()}
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getLastAccessedTime()}.
*/
static final String LAST_ACCESSED_ATTR = "lastAccessedTime";
@@ -288,7 +289,7 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
*/
private String keyPrefix = DEFAULT_SPRING_SESSION_REDIS_PREFIX;
private final RedisOperations<Object,Object> sessionRedisOperations;
private final RedisOperations<Object, Object> sessionRedisOperations;
private final RedisSessionExpirationPolicy expirationPolicy;
@@ -376,14 +377,14 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
public void save(RedisSession session) {
session.saveDelta();
if(session.isNew()) {
if (session.isNew()) {
String sessionCreatedKey = getSessionCreatedChannel(session.getId());
this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
session.setNew(false);
}
}
@Scheduled(cron="0 * * * * *")
@Scheduled(cron = "0 * * * * *")
public void cleanupExpiredSessions() {
this.expirationPolicy.cleanExpiredSessions();
}
@@ -392,16 +393,16 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
return getSession(id, false);
}
public Map<String,RedisSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
if(!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) {
public Map<String, RedisSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) {
return Collections.emptyMap();
}
String principalKey = getPrincipalKey(indexValue);
Set<Object> sessionIds = sessionRedisOperations.boundSetOps(principalKey).members();
Map<String,RedisSession> sessions = new HashMap<String,RedisSession>(sessionIds.size());
for(Object id : sessionIds) {
Set<Object> sessionIds = this.sessionRedisOperations.boundSetOps(principalKey).members();
Map<String, RedisSession> sessions = new HashMap<String, RedisSession>(sessionIds.size());
for (Object id : sessionIds) {
RedisSession session = getSession((String) id);
if(session != null) {
if (session != null) {
sessions.put(session.getId(), session);
}
}
@@ -409,21 +410,21 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
}
/**
*
* Gets the session.
* @param id the session id
* @param allowExpired
* if true, will also include expired sessions that have not been
* deleted. If false, will ensure expired sessions are not
* returned.
* @return
* @return the Redis session
*/
private RedisSession getSession(String id, boolean allowExpired) {
Map<Object, Object> entries = getSessionBoundHashOperations(id).entries();
if(entries.isEmpty()) {
if (entries.isEmpty()) {
return null;
}
MapSession loaded = loadSession(id, entries);
if(!allowExpired && loaded.isExpired()) {
if (!allowExpired && loaded.isExpired()) {
return null;
}
RedisSession result = new RedisSession(loaded);
@@ -433,15 +434,18 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
private MapSession loadSession(String id, Map<Object, Object> entries) {
MapSession loaded = new MapSession(id);
for(Map.Entry<Object,Object> entry : entries.entrySet()) {
for (Map.Entry<Object, Object> entry : entries.entrySet()) {
String key = (String) entry.getKey();
if(CREATION_TIME_ATTR.equals(key)) {
if (CREATION_TIME_ATTR.equals(key)) {
loaded.setCreationTime((Long) entry.getValue());
} else if(MAX_INACTIVE_ATTR.equals(key)) {
}
else if (MAX_INACTIVE_ATTR.equals(key)) {
loaded.setMaxInactiveIntervalInSeconds((Integer) entry.getValue());
} else if(LAST_ACCESSED_ATTR.equals(key)) {
}
else if (LAST_ACCESSED_ATTR.equals(key)) {
loaded.setLastAccessedTime((Long) entry.getValue());
} else if(key.startsWith(SESSION_ATTR_PREFIX)) {
}
else if (key.startsWith(SESSION_ATTR_PREFIX)) {
loaded.setAttribute(key.substring(SESSION_ATTR_PREFIX.length()), entry.getValue());
}
}
@@ -450,12 +454,12 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
public void delete(String sessionId) {
RedisSession session = getSession(sessionId, true);
if(session == null) {
if (session == null) {
return;
}
cleanupPrincipalIndex(session);
expirationPolicy.onDelete(session);
this.expirationPolicy.onDelete(session);
String expireKey = getExpiredKey(session.getId());
this.sessionRedisOperations.delete(expireKey);
@@ -466,8 +470,8 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
public RedisSession createSession() {
RedisSession redisSession = new RedisSession();
if(defaultMaxInactiveInterval != null) {
redisSession.setMaxInactiveIntervalInSeconds(defaultMaxInactiveInterval);
if (this.defaultMaxInactiveInterval != null) {
redisSession.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval);
}
return redisSession;
}
@@ -476,42 +480,43 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
public void onMessage(Message message, byte[] pattern) {
byte[] messageChannel = message.getChannel();
byte[] messageBody = message.getBody();
if(messageChannel == null || messageBody == null) {
if (messageChannel == null || messageBody == null) {
return;
}
String channel = new String(messageChannel);
if(channel.startsWith(getSessionCreatedChannelPrefix())) {
if (channel.startsWith(getSessionCreatedChannelPrefix())) {
// TODO: is this thread safe?
Map<Object,Object> loaded = (Map<Object, Object>) defaultSerializer.deserialize(message.getBody());
Map<Object, Object> loaded = (Map<Object, Object>) this.defaultSerializer.deserialize(message.getBody());
handleCreated(loaded, channel);
return;
}
String body = new String(messageBody);
if(!body.startsWith(getExpiredKeyPrefix())) {
if (!body.startsWith(getExpiredKeyPrefix())) {
return;
}
boolean isDeleted = channel.endsWith(":del");
if(isDeleted || channel.endsWith(":expired")) {
if (isDeleted || channel.endsWith(":expired")) {
int beginIndex = body.lastIndexOf(":") + 1;
int endIndex = body.length();
String sessionId = body.substring(beginIndex, endIndex);
RedisSession session = getSession(sessionId, true);
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Publishing SessionDestroyedEvent for session " + sessionId);
}
cleanupPrincipalIndex(session);
if(isDeleted) {
if (isDeleted) {
handleDeleted(sessionId, session);
} else {
}
else {
handleExpired(sessionId, session);
}
@@ -520,34 +525,36 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
}
private void cleanupPrincipalIndex(RedisSession session) {
if(session == null) {
if (session == null) {
return;
}
String sessionId = session.getId();
String principal = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(session);
if(principal != null) {
sessionRedisOperations.boundSetOps(getPrincipalKey(principal)).remove(sessionId);
if (principal != null) {
this.sessionRedisOperations.boundSetOps(getPrincipalKey(principal)).remove(sessionId);
}
}
public void handleCreated(Map<Object,Object> loaded, String channel) {
public void handleCreated(Map<Object, Object> loaded, String channel) {
String id = channel.substring(channel.lastIndexOf(":") + 1);
ExpiringSession session = loadSession(id, loaded);
publishEvent(new SessionCreatedEvent(this, session));
}
private void handleDeleted(String sessionId, RedisSession session) {
if(session == null) {
if (session == null) {
publishEvent(new SessionDeletedEvent(this, sessionId));
} else {
}
else {
publishEvent(new SessionDeletedEvent(this, session));
}
}
private void handleExpired(String sessionId, RedisSession session) {
if(session == null) {
if (session == null) {
publishEvent(new SessionExpiredEvent(this, sessionId));
} else {
}
else {
publishEvent(new SessionExpiredEvent(this, session));
}
}
@@ -605,7 +612,7 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
}
/**
* Gets the {@link BoundHashOperations} to operate on a {@link Session}
* Gets the {@link BoundHashOperations} to operate on a {@link Session}.
* @param sessionId the id of the {@link Session} to work with
* @return the {@link BoundHashOperations} to operate on a {@link Session}
*/
@@ -615,17 +622,17 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
}
/**
* Gets the key for the specified session attribute
* Gets the key for the specified session attribute.
*
* @param attributeName
* @return
* @param attributeName the attribute name
* @return the attribute key name
*/
static String getSessionAttrNameKey(String attributeName) {
return SESSION_ATTR_PREFIX + attributeName;
}
private static RedisTemplate<Object,Object> createDefaultTemplate(RedisConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory,"connectionFactory cannot be null");
private static RedisTemplate<Object, Object> createDefaultTemplate(RedisConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory, "connectionFactory cannot be null");
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
@@ -640,13 +647,13 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
* {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#saveDelta()} is invoked
* all the attributes that have been changed will be persisted.
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
final class RedisSession implements ExpiringSession {
private final MapSession cached;
private Long originalLastAccessTime;
private Map<String, Object> delta = new HashMap<String,Object>();
private Map<String, Object> delta = new HashMap<String, Object>();
private boolean isNew;
private String originalPrincipalName;
@@ -655,15 +662,15 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
*/
RedisSession() {
this(new MapSession());
delta.put(CREATION_TIME_ATTR, getCreationTime());
delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
this.delta.put(CREATION_TIME_ATTR, getCreationTime());
this.delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
this.isNew = true;
flushImmediateIfNecessary();
}
/**
* Creates a new instance from the provided {@link MapSession}
* Creates a new instance from the provided {@link MapSession}.
*
* @param cached the {@MapSession} that represents the persisted session that was retrieved. Cannot be null.
*/
@@ -678,64 +685,64 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
}
public void setLastAccessedTime(long lastAccessedTime) {
cached.setLastAccessedTime(lastAccessedTime);
delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
this.cached.setLastAccessedTime(lastAccessedTime);
this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
flushImmediateIfNecessary();
}
public boolean isExpired() {
return cached.isExpired();
return this.cached.isExpired();
}
public boolean isNew() {
return isNew;
return this.isNew;
}
public long getCreationTime() {
return cached.getCreationTime();
return this.cached.getCreationTime();
}
public String getId() {
return cached.getId();
return this.cached.getId();
}
public long getLastAccessedTime() {
return cached.getLastAccessedTime();
return this.cached.getLastAccessedTime();
}
public void setMaxInactiveIntervalInSeconds(int interval) {
cached.setMaxInactiveIntervalInSeconds(interval);
delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
this.cached.setMaxInactiveIntervalInSeconds(interval);
this.delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
flushImmediateIfNecessary();
}
public int getMaxInactiveIntervalInSeconds() {
return cached.getMaxInactiveIntervalInSeconds();
return this.cached.getMaxInactiveIntervalInSeconds();
}
@SuppressWarnings("unchecked")
public Object getAttribute(String attributeName) {
return cached.getAttribute(attributeName);
return this.cached.getAttribute(attributeName);
}
public Set<String> getAttributeNames() {
return cached.getAttributeNames();
return this.cached.getAttributeNames();
}
public void setAttribute(String attributeName, Object attributeValue) {
cached.setAttribute(attributeName, attributeValue);
delta.put(getSessionAttrNameKey(attributeName), attributeValue);
this.cached.setAttribute(attributeName, attributeValue);
this.delta.put(getSessionAttrNameKey(attributeName), attributeValue);
flushImmediateIfNecessary();
}
public void removeAttribute(String attributeName) {
cached.removeAttribute(attributeName);
delta.put(getSessionAttrNameKey(attributeName), null);
this.cached.removeAttribute(attributeName);
this.delta.put(getSessionAttrNameKey(attributeName), null);
flushImmediateIfNecessary();
}
private void flushImmediateIfNecessary() {
if(redisFlushMode == RedisFlushMode.IMMEDIATE) {
if (RedisOperationsSessionRepository.this.redisFlushMode == RedisFlushMode.IMMEDIATE) {
saveDelta();
}
}
@@ -745,40 +752,43 @@ public class RedisOperationsSessionRepository implements FindByIndexNameSessionR
*/
private void saveDelta() {
String sessionId = getId();
getSessionBoundHashOperations(sessionId).putAll(delta);
getSessionBoundHashOperations(sessionId).putAll(this.delta);
String principalSessionKey = getSessionAttrNameKey(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
String securityPrincipalSessionKey = getSessionAttrNameKey(SPRING_SECURITY_CONTEXT);
if(delta.containsKey(principalSessionKey) || delta.containsKey(securityPrincipalSessionKey)) {
if(originalPrincipalName != null) {
String originalPrincipalRedisKey = getPrincipalKey((String) originalPrincipalName);
sessionRedisOperations.boundSetOps(originalPrincipalRedisKey).remove(sessionId);
if (this.delta.containsKey(principalSessionKey) || this.delta.containsKey(securityPrincipalSessionKey)) {
if (this.originalPrincipalName != null) {
String originalPrincipalRedisKey = getPrincipalKey((String) this.originalPrincipalName);
RedisOperationsSessionRepository.this.sessionRedisOperations.boundSetOps(originalPrincipalRedisKey).remove(sessionId);
}
String principal = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this);
originalPrincipalName = principal;
if(principal != null) {
this.originalPrincipalName = principal;
if (principal != null) {
String principalRedisKey = getPrincipalKey(principal);
sessionRedisOperations.boundSetOps(principalRedisKey).add(sessionId);
RedisOperationsSessionRepository.this.sessionRedisOperations.boundSetOps(principalRedisKey).add(sessionId);
}
}
delta = new HashMap<String,Object>(delta.size());
this.delta = new HashMap<String, Object>(this.delta.size());
Long originalExpiration = originalLastAccessTime == null ? null : originalLastAccessTime + TimeUnit.SECONDS.toMillis(getMaxInactiveIntervalInSeconds()) ;
expirationPolicy.onExpirationUpdated(originalExpiration, this);
Long originalExpiration = this.originalLastAccessTime == null ? null : this.originalLastAccessTime + TimeUnit.SECONDS.toMillis(getMaxInactiveIntervalInSeconds());
RedisOperationsSessionRepository.this.expirationPolicy.onExpirationUpdated(originalExpiration, this);
}
}
/**
* Principal name resolver helper class.
*/
static class PrincipalNameResolver {
private SpelExpressionParser parser = new SpelExpressionParser();
public String resolvePrincipal(Session session) {
String principalName = session.getAttribute(PRINCIPAL_NAME_INDEX_NAME);
if(principalName != null) {
if (principalName != null) {
return principalName;
}
Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT);
if(authentication != null) {
Expression expression = parser.parseExpression("authentication?.name");
if (authentication != null) {
Expression expression = this.parser.parseExpression("authentication?.name");
return expression.getValue(authentication, String.class);
}
return null;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.redis;
import java.util.Calendar;
@@ -22,6 +23,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.session.ExpiringSession;
@@ -49,12 +51,12 @@ final class RedisSessionExpirationPolicy {
private static final Log logger = LogFactory.getLog(RedisSessionExpirationPolicy.class);
private final RedisOperations<Object,Object> redis;
private final RedisOperations<Object, Object> redis;
private final RedisOperationsSessionRepository redisSession;
public RedisSessionExpirationPolicy(
RedisOperations<Object,Object> sessionRedisOperations, RedisOperationsSessionRepository redisSession) {
RedisSessionExpirationPolicy(
RedisOperations<Object, Object> sessionRedisOperations, RedisOperationsSessionRepository redisSession) {
super();
this.redis = sessionRedisOperations;
this.redisSession = redisSession;
@@ -63,23 +65,23 @@ final class RedisSessionExpirationPolicy {
public void onDelete(ExpiringSession session) {
long toExpire = roundUpToNextMinute(expiresInMillis(session));
String expireKey = getExpirationKey(toExpire);
redis.boundSetOps(expireKey).remove(session.getId());
this.redis.boundSetOps(expireKey).remove(session.getId());
}
public void onExpirationUpdated(Long originalExpirationTimeInMilli, ExpiringSession session) {
String keyToExpire = "expires:" + session.getId();
long toExpire = roundUpToNextMinute(expiresInMillis(session));
if(originalExpirationTimeInMilli != null) {
if (originalExpirationTimeInMilli != null) {
long originalRoundedUp = roundUpToNextMinute(originalExpirationTimeInMilli);
if(toExpire != originalRoundedUp) {
if (toExpire != originalRoundedUp) {
String expireKey = getExpirationKey(originalRoundedUp);
redis.boundSetOps(expireKey).remove(keyToExpire);
this.redis.boundSetOps(expireKey).remove(keyToExpire);
}
}
String expireKey = getExpirationKey(toExpire);
BoundSetOperations<Object, Object> expireOperations = redis.boundSetOps(expireKey);
BoundSetOperations<Object, Object> expireOperations = this.redis.boundSetOps(expireKey);
expireOperations.add(keyToExpire);
long sessionExpireInSeconds = session.getMaxInactiveIntervalInSeconds();
@@ -87,13 +89,14 @@ final class RedisSessionExpirationPolicy {
String sessionKey = getSessionKey(keyToExpire);
expireOperations.expire(fiveMinutesAfterExpires, TimeUnit.SECONDS);
if(sessionExpireInSeconds == 0) {
redis.delete(sessionKey);
} else {
redis.boundValueOps(sessionKey).append("");
redis.boundValueOps(sessionKey).expire(sessionExpireInSeconds, TimeUnit.SECONDS);
if (sessionExpireInSeconds == 0) {
this.redis.delete(sessionKey);
}
redis.boundHashOps(getSessionKey(session.getId())).expire(fiveMinutesAfterExpires, TimeUnit.SECONDS);
else {
this.redis.boundValueOps(sessionKey).append("");
this.redis.boundValueOps(sessionKey).expire(sessionExpireInSeconds, TimeUnit.SECONDS);
}
this.redis.boundHashOps(getSessionKey(session.getId())).expire(fiveMinutesAfterExpires, TimeUnit.SECONDS);
}
String getExpirationKey(long expires) {
@@ -108,14 +111,14 @@ final class RedisSessionExpirationPolicy {
long now = System.currentTimeMillis();
long prevMin = roundDownMinute(now);
if(logger.isDebugEnabled()) {
logger.debug("Cleaning up sessions expiring at "+ new Date(prevMin));
if (logger.isDebugEnabled()) {
logger.debug("Cleaning up sessions expiring at " + new Date(prevMin));
}
String expirationKey = getExpirationKey(prevMin);
Set<Object> sessionsToExpire = redis.boundSetOps(expirationKey).members();
redis.delete(expirationKey);
for(Object session : sessionsToExpire) {
Set<Object> sessionsToExpire = this.redis.boundSetOps(expirationKey).members();
this.redis.delete(expirationKey);
for (Object session : sessionsToExpire) {
String sessionKey = getSessionKey((String) session);
touch(sessionKey);
}
@@ -125,10 +128,10 @@ final class RedisSessionExpirationPolicy {
* By trying to access the session we only trigger a deletion if it the TTL is expired. This is done to handle
* https://github.com/spring-projects/spring-session/issues/93
*
* @param key
* @param key the key
*/
private void touch(String key) {
redis.hasKey(key);
this.redis.hasKey(key);
}
static long expiresInMillis(ExpiringSession session) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.redis;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.connection.Message;
@@ -42,7 +44,7 @@ public class SessionMessageListener implements MessageListener {
private final ApplicationEventPublisher eventPublisher;
/**
* Creates a new instance
* Creates a new instance.
*
* @param eventPublisher the {@link ApplicationEventPublisher} to use. Cannot be null.
*/
@@ -54,15 +56,15 @@ public class SessionMessageListener implements MessageListener {
public void onMessage(Message message, byte[] pattern) {
byte[] messageChannel = message.getChannel();
byte[] messageBody = message.getBody();
if(messageChannel == null || messageBody == null) {
if (messageChannel == null || messageBody == null) {
return;
}
String channel = new String(messageChannel);
if(!(channel.endsWith(":del") || channel.endsWith(":expired"))) {
if (!(channel.endsWith(":del") || channel.endsWith(":expired"))) {
return;
}
String body = new String(messageBody);
if(!body.startsWith("spring:session:sessions:")) {
if (!body.startsWith("spring:session:sessions:")) {
return;
}
@@ -70,13 +72,14 @@ public class SessionMessageListener implements MessageListener {
int endIndex = body.length();
String sessionId = body.substring(beginIndex, endIndex);
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Publishing SessionDestroyedEvent for session " + sessionId);
}
if(channel.endsWith(":del")) {
if (channel.endsWith(":del")) {
publishEvent(new SessionDeletedEvent(this, sessionId));
} else {
}
else {
publishEvent(new SessionExpiredEvent(this, sessionId));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.redis.config;
import java.util.List;
@@ -49,17 +50,17 @@ public class ConfigureNotifyKeyspaceEventsAction implements ConfigureRedisAction
public void configure(RedisConnection connection) {
String notifyOptions = getNotifyOptions(connection);
String customizedNotifyOptions = notifyOptions;
if(!customizedNotifyOptions.contains("E")) {
if (!customizedNotifyOptions.contains("E")) {
customizedNotifyOptions += "E";
}
boolean A = customizedNotifyOptions.contains("A");
if(!(A || customizedNotifyOptions.contains("g"))) {
if (!(A || customizedNotifyOptions.contains("g"))) {
customizedNotifyOptions += "g";
}
if(!(A || customizedNotifyOptions.contains("x"))) {
if (!(A || customizedNotifyOptions.contains("x"))) {
customizedNotifyOptions += "x";
}
if(!notifyOptions.equals(customizedNotifyOptions)) {
if (!notifyOptions.equals(customizedNotifyOptions)) {
connection.setConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS, customizedNotifyOptions);
}
}
@@ -67,11 +68,12 @@ public class ConfigureNotifyKeyspaceEventsAction implements ConfigureRedisAction
private String getNotifyOptions(RedisConnection connection) {
try {
List<String> config = connection.getConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS);
if(config.size() < 2) {
if (config.size() < 2) {
return "";
}
return config.get(1);
} catch(InvalidDataAccessApiUsageException e) {
}
catch (InvalidDataAccessApiUsageException e) {
throw new IllegalStateException("Unable to configure Redis to keyspace notifications. See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent", e);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.redis.config;
import org.springframework.data.redis.connection.RedisConnection;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.redis.config.annotation.web.http;
import java.lang.annotation.Documented;
@@ -52,8 +53,8 @@ import org.springframework.session.data.redis.RedisFlushMode;
* @since 1.0
* @see EnableSpringHttpSession
*/
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.TYPE})
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration
@@ -96,4 +97,4 @@ public @interface EnableRedisHttpSession {
* @since 1.1
*/
RedisFlushMode redisFlushMode() default RedisFlushMode.ON_SAVE;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.redis.config.annotation.web.http;
import java.util.Arrays;
@@ -80,11 +81,11 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
if (redisTaskExecutor != null) {
container.setTaskExecutor(redisTaskExecutor);
if (this.redisTaskExecutor != null) {
container.setTaskExecutor(this.redisTaskExecutor);
}
if (redisSubscriptionExecutor != null) {
container.setSubscriptionExecutor(redisSubscriptionExecutor);
if (this.redisSubscriptionExecutor != null) {
container.setSubscriptionExecutor(this.redisSubscriptionExecutor);
}
container.addMessageListener(messageListener,
Arrays.asList(new PatternTopic("__keyevent@*:del"), new PatternTopic("__keyevent@*:expired")));
@@ -93,12 +94,12 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio
}
@Bean
public RedisTemplate<Object,Object> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
public RedisTemplate<Object, Object> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
if(defaultRedisSerializer != null) {
template.setDefaultSerializer(defaultRedisSerializer);
if (this.defaultRedisSerializer != null) {
template.setDefaultSerializer(this.defaultRedisSerializer);
}
template.setConnectionFactory(connectionFactory);
return template;
@@ -108,17 +109,17 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio
public RedisOperationsSessionRepository sessionRepository(@Qualifier("sessionRedisTemplate") RedisOperations<Object, Object> sessionRedisTemplate, ApplicationEventPublisher applicationEventPublisher) {
RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
sessionRepository.setApplicationEventPublisher(applicationEventPublisher);
sessionRepository.setDefaultMaxInactiveInterval(maxInactiveIntervalInSeconds);
if(defaultRedisSerializer != null) {
sessionRepository.setDefaultSerializer(defaultRedisSerializer);
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
if (this.defaultRedisSerializer != null) {
sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
}
String redisNamespace = getRedisNamespace();
if(StringUtils.hasText(redisNamespace)) {
if (StringUtils.hasText(redisNamespace)) {
sessionRepository.setRedisKeyNamespace(redisNamespace);
}
sessionRepository.setRedisFlushMode(redisFlushMode);
sessionRepository.setRedisFlushMode(this.redisFlushMode);
return sessionRepository;
}
@@ -136,45 +137,24 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio
}
private String getRedisNamespace() {
if(StringUtils.hasText(this.redisNamespace)) {
if (StringUtils.hasText(this.redisNamespace)) {
return this.redisNamespace;
}
return System.getProperty("spring.session.redis.namespace","");
return System.getProperty("spring.session.redis.namespace", "");
}
public void setImportMetadata(AnnotationMetadata importMetadata) {
Map<String, Object> enableAttrMap = importMetadata.getAnnotationAttributes(EnableRedisHttpSession.class.getName());
AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap);
maxInactiveIntervalInSeconds = enableAttrs.getNumber("maxInactiveIntervalInSeconds");
this.maxInactiveIntervalInSeconds = enableAttrs.getNumber("maxInactiveIntervalInSeconds");
this.redisNamespace = enableAttrs.getString("redisNamespace");
this.redisFlushMode = enableAttrs.getEnum("redisFlushMode");
}
@Bean
public InitializingBean enableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory) {
return new EnableRedisKeyspaceNotificationsInitializer(connectionFactory, configureRedisAction);
}
/**
* Ensures that Redis is configured to send keyspace notifications. This is important to ensure that expiration and
* deletion of sessions trigger SessionDestroyedEvents. Without the SessionDestroyedEvent resources may not get
* cleaned up properly. For example, the mapping of the Session to WebSocket connections may not get cleaned up.
*/
static class EnableRedisKeyspaceNotificationsInitializer implements InitializingBean {
private final RedisConnectionFactory connectionFactory;
private ConfigureRedisAction configure;
EnableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory, ConfigureRedisAction configure) {
this.connectionFactory = connectionFactory;
this.configure = configure;
}
public void afterPropertiesSet() throws Exception {
RedisConnection connection = connectionFactory.getConnection();
configure.configure(connection);
}
return new EnableRedisKeyspaceNotificationsInitializer(connectionFactory, this.configureRedisAction);
}
/**
@@ -204,4 +184,26 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio
public void setRedisSubscriptionExecutor(Executor redisSubscriptionExecutor) {
this.redisSubscriptionExecutor = redisSubscriptionExecutor;
}
/**
* Ensures that Redis is configured to send keyspace notifications. This is important to ensure that expiration and
* deletion of sessions trigger SessionDestroyedEvents. Without the SessionDestroyedEvent resources may not get
* cleaned up properly. For example, the mapping of the Session to WebSocket connections may not get cleaned up.
*/
static class EnableRedisKeyspaceNotificationsInitializer implements InitializingBean {
private final RedisConnectionFactory connectionFactory;
private ConfigureRedisAction configure;
EnableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory, ConfigureRedisAction configure) {
this.connectionFactory = connectionFactory;
this.configure = configure;
}
public void afterPropertiesSet() throws Exception {
RedisConnection connection = this.connectionFactory.getConnection();
this.configure.configure(connection);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.events;
import org.springframework.context.ApplicationEvent;
@@ -38,7 +39,7 @@ public abstract class AbstractSessionEvent extends ApplicationEvent {
this.session = null;
}
AbstractSessionEvent(Object source, Session session) {
AbstractSessionEvent(Object source, Session session) {
super(source);
this.session = session;
this.sessionId = session.getId();
@@ -54,10 +55,10 @@ public abstract class AbstractSessionEvent extends ApplicationEvent {
*/
@SuppressWarnings("unchecked")
public <S extends Session> S getSession() {
return (S) session;
return (S) this.session;
}
public String getSessionId() {
return sessionId;
return this.sessionId;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.events;
import org.springframework.session.Session;
@@ -35,6 +36,7 @@ public class SessionCreatedEvent extends AbstractSessionEvent {
}
/**
* Create a new {@link SessionCreatedEvent}.
* @param source The Source of the SessionCreatedEvent
* @param session the Session that was created
*/
@@ -42,4 +44,4 @@ public class SessionCreatedEvent extends AbstractSessionEvent {
super(source, session);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.events;
import org.springframework.session.Session;
@@ -37,4 +38,4 @@ public class SessionDeletedEvent extends SessionDestroyedEvent {
public SessionDeletedEvent(Object source, Session session) {
super(source, session);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.events;
import org.springframework.session.Session;
@@ -32,10 +33,11 @@ public class SessionDestroyedEvent extends AbstractSessionEvent {
}
/**
* Create a new {@link SessionDestroyedEvent}.
* @param source The Source of the SessionDestoryedEvent
* @param session the Session that was created
*/
public SessionDestroyedEvent(Object source, Session session) {
super(source, session);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.events;
import org.springframework.session.Session;
@@ -37,4 +38,4 @@ public class SessionExpiredEvent extends SessionDestroyedEvent {
public SessionExpiredEvent(Object source, Session session) {
super(source, session);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,10 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.hazelcast;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.map.listener.EntryAddedListener;
import com.hazelcast.map.listener.EntryEvictedListener;
import com.hazelcast.map.listener.EntryRemovedListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.session.ExpiringSession;
import org.springframework.session.events.SessionCreatedEvent;
@@ -24,11 +30,6 @@ import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.map.listener.EntryAddedListener;
import com.hazelcast.map.listener.EntryEvictedListener;
import com.hazelcast.map.listener.EntryRemovedListener;
/**
* Listen for events on the Hazelcast-backed SessionRepository and
* translate those events into the corresponding Spring Session events.
@@ -55,21 +56,21 @@ public class SessionEntryListener implements EntryAddedListener<String, Expiring
}
public void entryAdded(EntryEvent<String, ExpiringSession> event) {
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Session created with id: " + event.getValue().getId());
}
this.eventPublisher.publishEvent(new SessionCreatedEvent(this, event.getValue()));
}
public void entryEvicted(EntryEvent<String, ExpiringSession> event) {
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Session expired with id: " + event.getOldValue().getId());
}
this.eventPublisher.publishEvent(new SessionExpiredEvent(this, event.getOldValue()));
}
public void entryRemoved(EntryEvent<String, ExpiringSession> event) {
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Session deleted with id: " + event.getOldValue().getId());
}
this.eventPublisher.publishEvent(new SessionDeletedEvent(this, event.getOldValue()));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.hazelcast.config.annotation.web.http;
import java.lang.annotation.Documented;
@@ -50,8 +51,8 @@ import org.springframework.session.config.annotation.web.http.EnableSpringHttpSe
* @since 1.1
* @see EnableSpringHttpSession
*/
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.TYPE})
@Documented
@Import(HazelcastHttpSessionConfiguration.class)
@Configuration

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.hazelcast.config.annotation.web.http;
import java.util.Collection;
@@ -22,6 +23,9 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -35,9 +39,6 @@ import org.springframework.session.config.annotation.web.http.SpringHttpSessionC
import org.springframework.session.hazelcast.SessionEntryListener;
import org.springframework.session.web.http.SessionRepositoryFilter;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
/**
* Exposes the {@link SessionRepositoryFilter} as a bean named
* "springSessionRepositoryFilter". In order to use this a single
@@ -60,11 +61,11 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
@Bean
public SessionRepository<ExpiringSession> sessionRepository(HazelcastInstance hazelcastInstance, SessionEntryListener sessionListener) {
this.sessionsMap = hazelcastInstance.getMap(sessionMapName);
this.sessionsMap = hazelcastInstance.getMap(this.sessionMapName);
this.sessionListenerUid = this.sessionsMap.addEntryListener(sessionListener, true);
MapSessionRepository sessionRepository = new MapSessionRepository(new ExpiringSessionMap(this.sessionsMap));
sessionRepository.setDefaultMaxInactiveInterval(maxInactiveIntervalInSeconds);
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
return sessionRepository;
}
@@ -99,69 +100,72 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
this.sessionMapName = sessionMapName;
}
/**
* A wrapper for Hazelcast's {@link IMap} which is used to store the sessions.
*/
static class ExpiringSessionMap implements Map<String, ExpiringSession> {
private IMap<String,ExpiringSession> delegate;
private IMap<String, ExpiringSession> delegate;
ExpiringSessionMap(IMap<String,ExpiringSession> delegate) {
ExpiringSessionMap(IMap<String, ExpiringSession> delegate) {
this.delegate = delegate;
}
public ExpiringSession put(String key, ExpiringSession value) {
if(value == null) {
return delegate.put(key, value);
if (value == null) {
return this.delegate.put(key, value);
}
return delegate.put(key, value, value.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
return this.delegate.put(key, value, value.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
}
public int size() {
return delegate.size();
return this.delegate.size();
}
public boolean isEmpty() {
return delegate.isEmpty();
return this.delegate.isEmpty();
}
public boolean containsKey(Object key) {
return delegate.containsKey(key);
return this.delegate.containsKey(key);
}
public boolean containsValue(Object value) {
return delegate.containsValue(value);
return this.delegate.containsValue(value);
}
public ExpiringSession get(Object key) {
return delegate.get(key);
return this.delegate.get(key);
}
public ExpiringSession remove(Object key) {
return delegate.remove(key);
return this.delegate.remove(key);
}
public void putAll(Map<? extends String, ? extends ExpiringSession> m) {
delegate.putAll(m);
this.delegate.putAll(m);
}
public void clear() {
delegate.clear();
this.delegate.clear();
}
public Set<String> keySet() {
return delegate.keySet();
return this.delegate.keySet();
}
public Collection<ExpiringSession> values() {
return delegate.values();
return this.delegate.values();
}
public Set<java.util.Map.Entry<String, ExpiringSession>> entrySet() {
return delegate.entrySet();
return this.delegate.entrySet();
}
public boolean equals(Object o) {
return delegate.equals(o);
return this.delegate.equals(o);
}
public int hashCode() {
return delegate.hashCode();
return this.delegate.hashCode();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.context;
import java.util.Arrays;
@@ -75,6 +76,9 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
private static final String SERVLET_CONTEXT_PREFIX = "org.springframework.web.servlet.FrameworkServlet.CONTEXT.";
/**
* The default name for Spring Session's repository filter.
*/
public static final String DEFAULT_FILTER_NAME = "springSessionRepositoryFilter";
private final Class<?>[] configurationClasses;
@@ -105,9 +109,9 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
public void onStartup(ServletContext servletContext)
throws ServletException {
beforeSessionRepositoryFilter(servletContext);
if(configurationClasses != null) {
if (this.configurationClasses != null) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(configurationClasses);
rootAppContext.register(this.configurationClasses);
servletContext.addListener(new ContextLoaderListener(rootAppContext));
}
insertSessionRepositoryFilter(servletContext);
@@ -115,14 +119,14 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
}
/**
* Registers the springSessionRepositoryFilter
* Registers the springSessionRepositoryFilter.
* @param servletContext the {@link ServletContext}
*/
private void insertSessionRepositoryFilter(ServletContext servletContext) {
String filterName = DEFAULT_FILTER_NAME;
DelegatingFilterProxy springSessionRepositoryFilter = new DelegatingFilterProxy(filterName);
String contextAttribute = getWebApplicationContextAttribute();
if(contextAttribute != null) {
if (contextAttribute != null) {
springSessionRepositoryFilter.setContextAttribute(contextAttribute);
}
registerFilter(servletContext, true, filterName, springSessionRepositoryFilter);
@@ -138,7 +142,7 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
* @param filters
* the {@link Filter}s to register
*/
protected final void insertFilters(ServletContext servletContext,Filter... filters) {
protected final void insertFilters(ServletContext servletContext, Filter... filters) {
registerFilters(servletContext, true, filters);
}
@@ -152,7 +156,7 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
* @param filters
* the {@link Filter}s to register
*/
protected final void appendFilters(ServletContext servletContext,Filter... filters) {
protected final void appendFilters(ServletContext servletContext, Filter... filters) {
registerFilters(servletContext, false, filters);
}
@@ -173,8 +177,8 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
private void registerFilters(ServletContext servletContext, boolean insertBeforeOtherFilters, Filter... filters) {
Assert.notEmpty(filters, "filters cannot be null or empty");
for(Filter filter : filters) {
if(filter == null) {
for (Filter filter : filters) {
if (filter == null) {
throw new IllegalArgumentException("filters cannot contain null values. Got " + Arrays.asList(filters));
}
String filterName = Conventions.getVariableName(filter);
@@ -185,15 +189,15 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
/**
* Registers the provided filter using the {@link #isAsyncSessionSupported()} and {@link #getSessionDispatcherTypes()}.
*
* @param servletContext
* @param servletContext the servlet context
* @param insertBeforeOtherFilters should this Filter be inserted before or after other {@link Filter}
* @param filterName
* @param filter
* @param filterName the filter name
* @param filter the filter
*/
private final void registerFilter(ServletContext servletContext, boolean insertBeforeOtherFilters, String filterName, Filter filter) {
private void registerFilter(ServletContext servletContext, boolean insertBeforeOtherFilters, String filterName, Filter filter) {
Dynamic registration = servletContext.addFilter(filterName, filter);
if(registration == null) {
throw new IllegalStateException("Duplicate Filter registration for '" + filterName +"'. Check to ensure the Filter is only configured once.");
if (registration == null) {
throw new IllegalStateException("Duplicate Filter registration for '" + filterName + "'. Check to ensure the Filter is only configured once.");
}
registration.setAsyncSupported(isAsyncSessionSupported());
EnumSet<DispatcherType> dispatcherTypes = getSessionDispatcherTypes();
@@ -217,7 +221,7 @@ public abstract class AbstractHttpSessionApplicationInitializer implements WebAp
*/
private String getWebApplicationContextAttribute() {
String dispatcherServletName = getDispatcherWebApplicationContextSuffix();
if(dispatcherServletName == null) {
if (dispatcherServletName == null) {
return null;
}
return SERVLET_CONTEXT_PREFIX + dispatcherServletName;

View File

@@ -1,18 +1,19 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session.web.http;
import java.io.UnsupportedEncodingException;
@@ -150,8 +151,8 @@ import org.springframework.util.Assert;
* }
*
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy, HttpSessionManager {
private static final String SESSION_IDS_WRITTEN_ATTR = CookieHttpSessionStrategy.class.getName().concat(".SESSIONS_WRITTEN_ATTR");
@@ -160,27 +161,27 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
static final String DEFAULT_SESSION_ALIAS_PARAM_NAME = "_s";
private Pattern ALIAS_PATTERN = Pattern.compile("^[\\w-]{1,50}$");
private static final Pattern ALIAS_PATTERN = Pattern.compile("^[\\w-]{1,50}$");
private String sessionParam = DEFAULT_SESSION_ALIAS_PARAM_NAME;
private CookieSerializer cookieSerializer = new DefaultCookieSerializer();
public String getRequestedSessionId(HttpServletRequest request) {
Map<String,String> sessionIds = getSessionIds(request);
Map<String, String> sessionIds = getSessionIds(request);
String sessionAlias = getCurrentSessionAlias(request);
return sessionIds.get(sessionAlias);
}
public String getCurrentSessionAlias(HttpServletRequest request) {
if(sessionParam == null) {
if (this.sessionParam == null) {
return DEFAULT_ALIAS;
}
String u = request.getParameter(sessionParam);
if(u == null) {
String u = request.getParameter(this.sessionParam);
if (u == null) {
return DEFAULT_ALIAS;
}
if(!ALIAS_PATTERN.matcher(u).matches()) {
if (!ALIAS_PATTERN.matcher(u).matches()) {
return DEFAULT_ALIAS;
}
return u;
@@ -188,13 +189,13 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
public String getNewSessionAlias(HttpServletRequest request) {
Set<String> sessionAliases = getSessionIds(request).keySet();
if(sessionAliases.isEmpty()) {
if (sessionAliases.isEmpty()) {
return DEFAULT_ALIAS;
}
long lastAlias = Long.decode(DEFAULT_ALIAS);
for(String alias : sessionAliases) {
for (String alias : sessionAliases) {
long selectedAlias = safeParse(alias);
if(selectedAlias > lastAlias) {
if (selectedAlias > lastAlias) {
lastAlias = selectedAlias;
}
}
@@ -204,30 +205,31 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
private long safeParse(String hex) {
try {
return Long.decode("0x" + hex);
} catch(NumberFormatException notNumber) {
}
catch (NumberFormatException notNumber) {
return 0;
}
}
public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {
Set<String> sessionIdsWritten = getSessionIdsWritten(request);
if(sessionIdsWritten.contains(session.getId())) {
if (sessionIdsWritten.contains(session.getId())) {
return;
}
sessionIdsWritten.add(session.getId());
Map<String,String> sessionIds = getSessionIds(request);
Map<String, String> sessionIds = getSessionIds(request);
String sessionAlias = getCurrentSessionAlias(request);
sessionIds.put(sessionAlias, session.getId());
String cookieValue = createSessionCookieValue(sessionIds);
cookieSerializer.writeCookieValue(new CookieValue(request,response,cookieValue));
this.cookieSerializer.writeCookieValue(new CookieValue(request, response, cookieValue));
}
@SuppressWarnings("unchecked")
private Set<String> getSessionIdsWritten(HttpServletRequest request) {
Set<String> sessionsWritten = (Set<String>) request.getAttribute(SESSION_IDS_WRITTEN_ATTR);
if(sessionsWritten == null) {
if (sessionsWritten == null) {
sessionsWritten = new HashSet<String>();
request.setAttribute(SESSION_IDS_WRITTEN_ATTR, sessionsWritten);
}
@@ -235,15 +237,15 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
}
private String createSessionCookieValue(Map<String, String> sessionIds) {
if(sessionIds.isEmpty()) {
if (sessionIds.isEmpty()) {
return "";
}
if(sessionIds.size() == 1 && sessionIds.keySet().contains(DEFAULT_ALIAS)) {
if (sessionIds.size() == 1 && sessionIds.keySet().contains(DEFAULT_ALIAS)) {
return sessionIds.values().iterator().next();
}
StringBuffer buffer = new StringBuffer();
for(Map.Entry<String,String> entry : sessionIds.entrySet()) {
for (Map.Entry<String, String> entry : sessionIds.entrySet()) {
String alias = entry.getKey();
String id = entry.getValue();
@@ -252,17 +254,17 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
buffer.append(id);
buffer.append(" ");
}
buffer.deleteCharAt(buffer.length()-1);
buffer.deleteCharAt(buffer.length() - 1);
return buffer.toString();
}
public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
Map<String,String> sessionIds = getSessionIds(request);
Map<String, String> sessionIds = getSessionIds(request);
String requestedAlias = getCurrentSessionAlias(request);
sessionIds.remove(requestedAlias);
String cookieValue = createSessionCookieValue(sessionIds);
cookieSerializer.writeCookieValue(new CookieValue(request,response,cookieValue));
this.cookieSerializer.writeCookieValue(new CookieValue(request, response, cookieValue));
}
/**
@@ -290,7 +292,7 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
}
/**
* Sets the name of the cookie to be used
* Sets the name of the cookie to be used.
* @param cookieName the name of the cookie to be used
* @deprecated use {@link #setCookieSerializer(CookieSerializer)}
*/
@@ -301,18 +303,18 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
this.cookieSerializer = serializer;
}
public Map<String,String> getSessionIds(HttpServletRequest request) {
List<String> cookieValues = cookieSerializer.readCookieValues(request);
public Map<String, String> getSessionIds(HttpServletRequest request) {
List<String> cookieValues = this.cookieSerializer.readCookieValues(request);
String sessionCookieValue = cookieValues.isEmpty() ? "" : cookieValues.iterator().next();
Map<String,String> result = new LinkedHashMap<String,String>();
Map<String, String> result = new LinkedHashMap<String, String>();
StringTokenizer tokens = new StringTokenizer(sessionCookieValue, " ");
if(tokens.countTokens() == 1) {
if (tokens.countTokens() == 1) {
result.put(DEFAULT_ALIAS, tokens.nextToken());
return result;
}
while(tokens.hasMoreTokens()) {
while (tokens.hasMoreTokens()) {
String alias = tokens.nextToken();
if(!tokens.hasMoreTokens()) {
if (!tokens.hasMoreTokens()) {
break;
}
String id = tokens.nextToken();
@@ -330,46 +332,23 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
return new MultiSessionHttpServletResponse(response, request);
}
class MultiSessionHttpServletResponse extends HttpServletResponseWrapper {
private final HttpServletRequest request;
public MultiSessionHttpServletResponse(HttpServletResponse response, HttpServletRequest request) {
super(response);
this.request = request;
}
@Override
public String encodeRedirectURL(String url) {
url = super.encodeRedirectURL(url);
return CookieHttpSessionStrategy.this.encodeURL(url, getCurrentSessionAlias(request));
}
@Override
public String encodeURL(String url) {
url = super.encodeURL(url);
String alias = getCurrentSessionAlias(request);
return CookieHttpSessionStrategy.this.encodeURL(url, alias);
}
}
public String encodeURL(String url, String sessionAlias) {
String encodedSessionAlias = urlEncode(sessionAlias);
int queryStart = url.indexOf("?");
boolean isDefaultAlias = DEFAULT_ALIAS.equals(encodedSessionAlias);
if(queryStart < 0) {
return isDefaultAlias ? url : url + "?" + sessionParam + "=" + encodedSessionAlias;
if (queryStart < 0) {
return isDefaultAlias ? url : url + "?" + this.sessionParam + "=" + encodedSessionAlias;
}
String path = url.substring(0, queryStart);
String query = url.substring(queryStart + 1, url.length());
String replacement = isDefaultAlias ? "" : "$1"+encodedSessionAlias;
query = query.replaceFirst( "((^|&)" + sessionParam + "=)([^&]+)?", replacement);
if(!isDefaultAlias && url.endsWith(query)) {
String replacement = isDefaultAlias ? "" : "$1" + encodedSessionAlias;
query = query.replaceFirst("((^|&)" + this.sessionParam + "=)([^&]+)?", replacement);
if (!isDefaultAlias && url.endsWith(query)) {
// no existing alias
if(!(query.endsWith("&") || query.length() == 0)) {
if (!(query.endsWith("&") || query.length() == 0)) {
query += "&";
}
query += sessionParam + "=" + encodedSessionAlias;
query += this.sessionParam + "=" + encodedSessionAlias;
}
return path + "?" + query;
@@ -378,8 +357,36 @@ public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy
private String urlEncode(String value) {
try {
return URLEncoder.encode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
/**
* A {@link CookieHttpSessionStrategy} aware {@link HttpServletResponseWrapper}.
*/
class MultiSessionHttpServletResponse extends HttpServletResponseWrapper {
private final HttpServletRequest request;
MultiSessionHttpServletResponse(HttpServletResponse response, HttpServletRequest request) {
super(response);
this.request = request;
}
@Override
public String encodeRedirectURL(String url) {
url = super.encodeRedirectURL(url);
return CookieHttpSessionStrategy.this.encodeURL(url, getCurrentSessionAlias(this.request));
}
@Override
public String encodeURL(String url) {
url = super.encodeURL(url);
String alias = getCurrentSessionAlias(this.request);
return CookieHttpSessionStrategy.this.encodeURL(url, alias);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.http;
import java.util.List;
@@ -32,7 +33,7 @@ public interface CookieSerializer {
/**
* Writes a given {@link CookieValue} to the provided
* {@link HttpServletResponse}
* {@link HttpServletResponse}.
*
* @param cookieValue
* the {@link CookieValue} to write to
@@ -61,13 +62,13 @@ public interface CookieSerializer {
* @author Rob Winch
* @since 1.1
*/
public class CookieValue {
class CookieValue {
private final HttpServletRequest request;
private final HttpServletResponse response;
private final String cookieValue;
/**
* Creates a new instance
* Creates a new instance.
*
* @param request
* the {@link HttpServletRequest} to use. Useful for
@@ -92,7 +93,7 @@ public interface CookieSerializer {
* @return the request to use. Cannot be null.
*/
public HttpServletRequest getRequest() {
return request;
return this.request;
}
/**
@@ -100,7 +101,7 @@ public interface CookieSerializer {
* @return the response to write to. Cannot be null.
*/
public HttpServletResponse getResponse() {
return response;
return this.response;
}
/**
@@ -109,7 +110,7 @@ public interface CookieSerializer {
* @return the value to be written
*/
public String getCookieValue() {
return cookieValue;
return this.cookieValue;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.http;
import java.util.ArrayList;
@@ -26,7 +27,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* The default implementation of {@link CookieSerializer}
* The default implementation of {@link CookieSerializer}.
*
* @author Rob Winch
* @since 1.1
@@ -53,17 +54,17 @@ public class DefaultCookieSerializer implements CookieSerializer {
* @see org.springframework.session.web.http.CookieSerializer#readCookieValues(javax.servlet.http.HttpServletRequest)
*/
public List<String> readCookieValues(HttpServletRequest request) {
Cookie cookies[] = request.getCookies();
Cookie[] cookies = request.getCookies();
List<String> matchingCookieValues = new ArrayList<String>();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookieName.equals(cookie.getName())) {
if (this.cookieName.equals(cookie.getName())) {
String sessionId = cookie.getValue();
if(sessionId == null) {
if (sessionId == null) {
continue;
}
if(jvmRoute != null && sessionId.endsWith(jvmRoute)) {
sessionId = sessionId.substring(0, sessionId.length() - jvmRoute.length());
if (this.jvmRoute != null && sessionId.endsWith(this.jvmRoute)) {
sessionId = sessionId.substring(0, sessionId.length() - this.jvmRoute.length());
}
matchingCookieValues.add(sessionId);
}
@@ -83,9 +84,9 @@ public class DefaultCookieSerializer implements CookieSerializer {
HttpServletResponse response = cookieValue.getResponse();
String requestedCookieValue = cookieValue.getCookieValue();
String actualCookieValue = jvmRoute == null ? requestedCookieValue : requestedCookieValue + jvmRoute;
String actualCookieValue = this.jvmRoute == null ? requestedCookieValue : requestedCookieValue + this.jvmRoute;
Cookie sessionCookie = new Cookie(cookieName, actualCookieValue);
Cookie sessionCookie = new Cookie(this.cookieName, actualCookieValue);
sessionCookie.setSecure(isSecureCookie(request));
sessionCookie.setPath(getCookiePath(request));
String domainName = getDomainName(request);
@@ -93,14 +94,15 @@ public class DefaultCookieSerializer implements CookieSerializer {
sessionCookie.setDomain(domainName);
}
if (useHttpOnlyCookie) {
if (this.useHttpOnlyCookie) {
sessionCookie.setHttpOnly(true);
}
if ("".equals(requestedCookieValue)) {
sessionCookie.setMaxAge(0);
} else {
sessionCookie.setMaxAge(cookieMaxAge);
}
else {
sessionCookie.setMaxAge(this.cookieMaxAge);
}
response.addCookie(sessionCookie);
@@ -125,17 +127,17 @@ public class DefaultCookieSerializer implements CookieSerializer {
* determines if the cookie should be marked as HTTP Only.
*/
public void setUseHttpOnlyCookie(boolean useHttpOnlyCookie) {
if(useHttpOnlyCookie && !isServlet3()) {
if (useHttpOnlyCookie && !isServlet3()) {
throw new IllegalArgumentException("You cannot set useHttpOnlyCookie to true in pre Servlet 3 environment");
}
this.useHttpOnlyCookie = useHttpOnlyCookie;
}
private boolean isSecureCookie(HttpServletRequest request) {
if (useSecureCookie == null) {
if (this.useSecureCookie == null) {
return request.isSecure();
}
return useSecureCookie;
return this.useSecureCookie;
}
/**
@@ -247,11 +249,11 @@ public class DefaultCookieSerializer implements CookieSerializer {
}
private String getDomainName(HttpServletRequest request) {
if (domainName != null) {
return domainName;
if (this.domainName != null) {
return this.domainName;
}
if (domainNamePattern != null) {
Matcher matcher = domainNamePattern.matcher(request.getServerName());
if (this.domainNamePattern != null) {
Matcher matcher = this.domainNamePattern.matcher(request.getServerName());
if (matcher.matches()) {
return matcher.group(1);
}
@@ -260,22 +262,23 @@ public class DefaultCookieSerializer implements CookieSerializer {
}
private String getCookiePath(HttpServletRequest request) {
if (cookiePath == null) {
if (this.cookiePath == null) {
return request.getContextPath() + "/";
}
return cookiePath;
return this.cookiePath;
}
/**
* Returns true if the Servlet 3 APIs are detected.
*
* @return
* @return whether the Servlet 3 APIs are detected
*/
private boolean isServlet3() {
try {
ServletRequest.class.getMethod("startAsync");
return true;
} catch (NoSuchMethodException e) {
}
catch (NoSuchMethodException e) {
}
return false;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.http;
import java.util.Collections;
@@ -29,6 +30,7 @@ import org.springframework.session.ExpiringSession;
/**
* Adapts Spring Session's {@link ExpiringSession} to an {@link HttpSession}.
*
* @param <S> the {@link ExpiringSession} type
* @author Rob Winch
* @since 1.1
*/
@@ -39,7 +41,7 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
private boolean invalidated;
private boolean old;
public ExpiringSessionHttpSession(S session, ServletContext servletContext) {
ExpiringSessionHttpSession(S session, ServletContext servletContext) {
this.session = session;
this.servletContext = servletContext;
}
@@ -49,33 +51,33 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
}
public S getSession() {
return session;
return this.session;
}
public long getCreationTime() {
checkState();
return session.getCreationTime();
return this.session.getCreationTime();
}
public String getId() {
return session.getId();
return this.session.getId();
}
public long getLastAccessedTime() {
checkState();
return session.getLastAccessedTime();
return this.session.getLastAccessedTime();
}
public ServletContext getServletContext() {
return servletContext;
return this.servletContext;
}
public void setMaxInactiveInterval(int interval) {
session.setMaxInactiveIntervalInSeconds(interval);
this.session.setMaxInactiveIntervalInSeconds(interval);
}
public int getMaxInactiveInterval() {
return session.getMaxInactiveIntervalInSeconds();
return this.session.getMaxInactiveIntervalInSeconds();
}
public HttpSessionContext getSessionContext() {
@@ -84,7 +86,7 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
public Object getAttribute(String name) {
checkState();
return session.getAttribute(name);
return this.session.getAttribute(name);
}
public Object getValue(String name) {
@@ -93,18 +95,18 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
public Enumeration<String> getAttributeNames() {
checkState();
return Collections.enumeration(session.getAttributeNames());
return Collections.enumeration(this.session.getAttributeNames());
}
public String[] getValueNames() {
checkState();
Set<String> attrs = session.getAttributeNames();
Set<String> attrs = this.session.getAttributeNames();
return attrs.toArray(new String[0]);
}
public void setAttribute(String name, Object value) {
checkState();
session.setAttribute(name, value);
this.session.setAttribute(name, value);
}
public void putValue(String name, Object value) {
@@ -113,7 +115,7 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
public void removeAttribute(String name) {
checkState();
session.removeAttribute(name);
this.session.removeAttribute(name);
}
public void removeValue(String name) {
@@ -131,11 +133,11 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
public boolean isNew() {
checkState();
return !old;
return !this.old;
}
private void checkState() {
if(invalidated) {
if (this.invalidated) {
throw new IllegalStateException("The HttpSession has already be invalidated.");
}
}

View File

@@ -1,26 +1,27 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session.web.http;
import org.springframework.session.Session;
import org.springframework.util.Assert;
package org.springframework.session.web.http;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.session.Session;
import org.springframework.util.Assert;
/**
* A {@link HttpSessionStrategy} that uses a header to obtain the session from. Specifically, this implementation will
* allow specifying a header name using {@link HeaderHttpSessionStrategy#setHeaderName(String)}. The default is "x-auth-token".
@@ -47,22 +48,22 @@ import javax.servlet.http.HttpServletResponse;
* x-auth-token:
* </pre>
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
public class HeaderHttpSessionStrategy implements HttpSessionStrategy {
private String headerName = "x-auth-token";
public String getRequestedSessionId(HttpServletRequest request) {
return request.getHeader(headerName);
return request.getHeader(this.headerName);
}
public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {
response.setHeader(headerName, session.getId());
response.setHeader(this.headerName, session.getId());
}
public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
response.setHeader(headerName, "");
response.setHeader(this.headerName, "");
}
/**
@@ -74,4 +75,4 @@ public class HeaderHttpSessionStrategy implements HttpSessionStrategy {
Assert.notNull(headerName, "headerName cannot be null");
this.headerName = headerName;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.http;
import java.util.Map;
@@ -39,7 +40,7 @@ public interface HttpSessionManager {
/**
* Gets a mapping of the session alias to the session id from the
* {@link HttpServletRequest}
* {@link HttpServletRequest}.
*
* @param request the {@link HttpServletRequest} to obtain the mapping from. Cannot be null.
* @return a mapping of the session alias to the session id from the

View File

@@ -1,30 +1,31 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session.web.http;
import org.springframework.session.Session;
package org.springframework.session.web.http;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.session.Session;
/**
* A strategy for mapping HTTP request and responses to a {@link Session}.
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
public interface HttpSessionStrategy {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.http;
import javax.servlet.http.HttpServletRequest;
@@ -28,10 +29,9 @@ import javax.servlet.http.HttpServletResponse;
* are active.
* </p>
*
* @see CookieHttpSessionStrategy
*
* @author Rob Winch
* @since 1.0
* @see CookieHttpSessionStrategy
*/
public interface MultiHttpSessionStrategy extends HttpSessionStrategy, RequestResponsePostProcessor {
}
}

View File

@@ -1,33 +1,38 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session.web.http;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Base class for response wrappers which encapsulate the logic for handling an event when the
* {@link javax.servlet.http.HttpServletResponse} is committed.
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
private final Log logger = LogFactory.getLog(getClass());
@@ -46,15 +51,16 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
private long contentWritten;
/**
* Create a new {@link OnCommittedResponseWrapper}.
* @param response the response to be wrapped
*/
public OnCommittedResponseWrapper(HttpServletResponse response) {
OnCommittedResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public void addHeader(String name, String value) {
if("Content-Length".equalsIgnoreCase(name)) {
if ("Content-Length".equalsIgnoreCase(name)) {
setContentLength(Long.parseLong(value));
}
super.addHeader(name, value);
@@ -81,13 +87,14 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
}
/**
* Implement the logic for handling the {@link javax.servlet.http.HttpServletResponse} being committed
* Implement the logic for handling the {@link javax.servlet.http.HttpServletResponse} being committed.
*/
protected abstract void onResponseCommitted();
/**
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before calling the
* superclass <code>sendError()</code>
* superclass <code>sendError()</code>.
* @param sc the error status code
*/
@Override
public final void sendError(int sc) throws IOException {
@@ -97,7 +104,8 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
/**
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before calling the
* superclass <code>sendError()</code>
* superclass <code>sendError()</code>.
* @param sc the error status code
*/
@Override
public final void sendError(int sc, String msg) throws IOException {
@@ -107,7 +115,8 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
/**
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before calling the
* superclass <code>sendRedirect()</code>
* superclass <code>sendRedirect()</code>.
* @param location the redirect URL location
*/
@Override
public final void sendRedirect(String location) throws IOException {
@@ -117,7 +126,8 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
/**
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before calling the calling
* <code>getOutputStream().close()</code> or <code>getOutputStream().flush()</code>
* <code>getOutputStream().close()</code> or <code>getOutputStream().flush()</code>.
* @throws IOException if an input or output exception occurred
*/
@Override
public ServletOutputStream getOutputStream() throws IOException {
@@ -126,7 +136,8 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
/**
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before calling the
* <code>getWriter().close()</code> or <code>getWriter().flush()</code>
* <code>getWriter().close()</code> or <code>getWriter().flush()</code>.
* @throws IOException if an input or output exception occurred
*/
@Override
public PrintWriter getWriter() throws IOException {
@@ -135,7 +146,8 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
/**
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before calling the
* superclass <code>flushBuffer()</code>
* superclass <code>flushBuffer()</code>.
* @throws IOException if an input or output exception occurred
*/
@Override
public void flushBuffer() throws IOException {
@@ -190,25 +202,26 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
* @param contentLengthToWrite the size of the content that is about to be written.
*/
private void checkContentLength(long contentLengthToWrite) {
contentWritten += contentLengthToWrite;
boolean isBodyFullyWritten = contentLength > 0 && contentWritten >= contentLength;
this.contentWritten += contentLengthToWrite;
boolean isBodyFullyWritten = this.contentLength > 0 && this.contentWritten >= this.contentLength;
int bufferSize = getBufferSize();
boolean requiresFlush = bufferSize > 0 && contentWritten >= bufferSize;
if(isBodyFullyWritten || requiresFlush) {
boolean requiresFlush = bufferSize > 0 && this.contentWritten >= bufferSize;
if (isBodyFullyWritten || requiresFlush) {
doOnResponseCommitted();
}
}
/**
* Calls <code>onResponseCommmitted()</code> with the current contents as long as
* {@link #disableOnResponseCommitted()()} was not invoked.
* {@link #disableOnResponseCommitted()} was not invoked.
*/
private void doOnResponseCommitted() {
if(!disableOnCommitted) {
if (!this.disableOnCommitted) {
onResponseCommitted();
disableOnResponseCommitted();
} else if(logger.isDebugEnabled()){
logger.debug("Skip invoking on");
}
else if (this.logger.isDebugEnabled()) {
this.logger.debug("Skip invoking on");
}
}
@@ -221,195 +234,195 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
private class SaveContextPrintWriter extends PrintWriter {
private final PrintWriter delegate;
public SaveContextPrintWriter(PrintWriter delegate) {
SaveContextPrintWriter(PrintWriter delegate) {
super(delegate);
this.delegate = delegate;
}
public void flush() {
doOnResponseCommitted();
delegate.flush();
this.delegate.flush();
}
public void close() {
doOnResponseCommitted();
delegate.close();
this.delegate.close();
}
public int hashCode() {
return delegate.hashCode();
return this.delegate.hashCode();
}
public boolean equals(Object obj) {
return delegate.equals(obj);
return this.delegate.equals(obj);
}
public String toString() {
return getClass().getName() + "[delegate=" + delegate.toString() + "]";
return getClass().getName() + "[delegate=" + this.delegate.toString() + "]";
}
public boolean checkError() {
return delegate.checkError();
return this.delegate.checkError();
}
public void write(int c) {
trackContentLength(c);
delegate.write(c);
this.delegate.write(c);
}
public void write(char[] buf, int off, int len) {
checkContentLength(len);
delegate.write(buf, off, len);
this.delegate.write(buf, off, len);
}
public void write(char[] buf) {
trackContentLength(buf);
delegate.write(buf);
this.delegate.write(buf);
}
public void write(String s, int off, int len) {
checkContentLength(len);
delegate.write(s, off, len);
this.delegate.write(s, off, len);
}
public void write(String s) {
trackContentLength(s);
delegate.write(s);
this.delegate.write(s);
}
public void print(boolean b) {
trackContentLength(b);
delegate.print(b);
this.delegate.print(b);
}
public void print(char c) {
trackContentLength(c);
delegate.print(c);
this.delegate.print(c);
}
public void print(int i) {
trackContentLength(i);
delegate.print(i);
this.delegate.print(i);
}
public void print(long l) {
trackContentLength(l);
delegate.print(l);
this.delegate.print(l);
}
public void print(float f) {
trackContentLength(f);
delegate.print(f);
this.delegate.print(f);
}
public void print(double d) {
trackContentLength(d);
delegate.print(d);
this.delegate.print(d);
}
public void print(char[] s) {
trackContentLength(s);
delegate.print(s);
this.delegate.print(s);
}
public void print(String s) {
trackContentLength(s);
delegate.print(s);
this.delegate.print(s);
}
public void print(Object obj) {
trackContentLength(obj);
delegate.print(obj);
this.delegate.print(obj);
}
public void println() {
trackContentLengthLn();
delegate.println();
this.delegate.println();
}
public void println(boolean x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(char x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(int x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(long x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(float x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(double x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(char[] x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(String x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public void println(Object x) {
trackContentLength(x);
trackContentLengthLn();
delegate.println(x);
this.delegate.println(x);
}
public PrintWriter printf(String format, Object... args) {
return delegate.printf(format, args);
return this.delegate.printf(format, args);
}
public PrintWriter printf(Locale l, String format, Object... args) {
return delegate.printf(l, format, args);
return this.delegate.printf(l, format, args);
}
public PrintWriter format(String format, Object... args) {
return delegate.format(format, args);
return this.delegate.format(format, args);
}
public PrintWriter format(Locale l, String format, Object... args) {
return delegate.format(l, format, args);
return this.delegate.format(l, format, args);
}
public PrintWriter append(CharSequence csq) {
checkContentLength(csq.length());
return delegate.append(csq);
return this.delegate.append(csq);
}
public PrintWriter append(CharSequence csq, int start, int end) {
checkContentLength(end - start);
return delegate.append(csq, start, end);
return this.delegate.append(csq, start, end);
}
public PrintWriter append(char c) {
trackContentLength(c);
return delegate.append(c);
return this.delegate.append(c);
}
}
@@ -423,7 +436,7 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
private class SaveContextServletOutputStream extends ServletOutputStream {
private final ServletOutputStream delegate;
public SaveContextServletOutputStream(ServletOutputStream delegate) {
SaveContextServletOutputStream(ServletOutputStream delegate) {
this.delegate = delegate;
}
@@ -434,116 +447,116 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
public void flush() throws IOException {
doOnResponseCommitted();
delegate.flush();
this.delegate.flush();
}
public void close() throws IOException {
doOnResponseCommitted();
delegate.close();
this.delegate.close();
}
public int hashCode() {
return delegate.hashCode();
return this.delegate.hashCode();
}
public boolean equals(Object obj) {
return delegate.equals(obj);
return this.delegate.equals(obj);
}
public void print(boolean b) throws IOException {
trackContentLength(b);
delegate.print(b);
this.delegate.print(b);
}
public void print(char c) throws IOException {
trackContentLength(c);
delegate.print(c);
this.delegate.print(c);
}
public void print(double d) throws IOException {
trackContentLength(d);
delegate.print(d);
this.delegate.print(d);
}
public void print(float f) throws IOException {
trackContentLength(f);
delegate.print(f);
this.delegate.print(f);
}
public void print(int i) throws IOException {
trackContentLength(i);
delegate.print(i);
this.delegate.print(i);
}
public void print(long l) throws IOException {
trackContentLength(l);
delegate.print(l);
this.delegate.print(l);
}
public void print(String s) throws IOException {
trackContentLength(s);
delegate.print(s);
this.delegate.print(s);
}
public void println() throws IOException {
trackContentLengthLn();
delegate.println();
this.delegate.println();
}
public void println(boolean b) throws IOException {
trackContentLength(b);
trackContentLengthLn();
delegate.println(b);
this.delegate.println(b);
}
public void println(char c) throws IOException {
trackContentLength(c);
trackContentLengthLn();
delegate.println(c);
this.delegate.println(c);
}
public void println(double d) throws IOException {
trackContentLength(d);
trackContentLengthLn();
delegate.println(d);
this.delegate.println(d);
}
public void println(float f) throws IOException {
trackContentLength(f);
trackContentLengthLn();
delegate.println(f);
this.delegate.println(f);
}
public void println(int i) throws IOException {
trackContentLength(i);
trackContentLengthLn();
delegate.println(i);
this.delegate.println(i);
}
public void println(long l) throws IOException {
trackContentLength(l);
trackContentLengthLn();
delegate.println(l);
this.delegate.println(l);
}
public void println(String s) throws IOException {
trackContentLength(s);
trackContentLengthLn();
delegate.println(s);
this.delegate.println(s);
}
public void write(byte[] b) throws IOException {
trackContentLength(b);
delegate.write(b);
this.delegate.write(b);
}
public void write(byte[] b, int off, int len) throws IOException {
checkContentLength(len);
delegate.write(b, off, len);
this.delegate.write(b, off, len);
}
public String toString() {
return getClass().getName() + "[delegate=" + delegate.toString() + "]";
return getClass().getName() + "[delegate=" + this.delegate.toString() + "]";
}
}
}
}

View File

@@ -1,31 +1,38 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session.web.http;
import javax.servlet.*;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Allows for easily ensuring that a request is only invoked once per request. This is a simplified version of spring-web's
* OncePerRequestFilter and copied to reduce the foot print required to use the session support.
*
* @since 1.0
* @author Rob Winch
* @since 1.0
*/
abstract class OncePerRequestFilter implements Filter {
/**
@@ -41,6 +48,11 @@ abstract class OncePerRequestFilter implements Filter {
* This {@code doFilter} implementation stores a request attribute for
* "already filtered", proceeding without filtering again if the
* attribute is already there.
* @param request the request
* @param response the response
* @param filterChain the filter chain
* @throws ServletException if request is not HTTP request
* @throws IOException in case of I/O operation exception
*/
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
@@ -50,7 +62,7 @@ abstract class OncePerRequestFilter implements Filter {
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
boolean hasAlreadyFilteredAttribute = request.getAttribute(this.alreadyFilteredAttributeName) != null;
if (hasAlreadyFilteredAttribute) {
@@ -60,13 +72,13 @@ abstract class OncePerRequestFilter implements Filter {
}
else {
// Do invoke this filter...
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
request.setAttribute(this.alreadyFilteredAttributeName, Boolean.TRUE);
try {
doFilterInternal(httpRequest, httpResponse, filterChain);
}
finally {
// Remove the "already filtered" request attribute for this request.
request.removeAttribute(alreadyFilteredAttributeName);
request.removeAttribute(this.alreadyFilteredAttributeName);
}
}
}
@@ -88,7 +100,9 @@ abstract class OncePerRequestFilter implements Filter {
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException;
public void init(FilterConfig config) {}
public void init(FilterConfig config) {
}
public void destroy() {}
public void destroy() {
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.http;
import javax.servlet.http.HttpServletRequest;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.http;
import java.util.List;
@@ -51,16 +52,17 @@ public class SessionEventHttpSessionListenerAdapter implements ApplicationListen
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(AbstractSessionEvent event) {
if(listeners.isEmpty()) {
if (this.listeners.isEmpty()) {
return;
}
HttpSessionEvent httpSessionEvent = createHttpSessionEvent(event);
for(HttpSessionListener listener : listeners) {
if(event instanceof SessionDestroyedEvent) {
for (HttpSessionListener listener : this.listeners) {
if (event instanceof SessionDestroyedEvent) {
listener.sessionDestroyed(httpSessionEvent);
} else if(event instanceof SessionCreatedEvent) {
}
else if (event instanceof SessionCreatedEvent) {
listener.sessionCreated(httpSessionEvent);
}
}
@@ -68,7 +70,7 @@ public class SessionEventHttpSessionListenerAdapter implements ApplicationListen
private HttpSessionEvent createHttpSessionEvent(AbstractSessionEvent event) {
ExpiringSession session = event.getSession();
HttpSession httpSession = new ExpiringSessionHttpSession<ExpiringSession>(session, context);
HttpSession httpSession = new ExpiringSessionHttpSession<ExpiringSession>(session, this.context);
HttpSessionEvent httpSessionEvent = new HttpSessionEvent(httpSession);
return httpSessionEvent;
}

View File

@@ -1,18 +1,19 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed 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
* Licensed 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
* 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.
* 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 org.springframework.session.web.http;
import java.io.IOException;
@@ -30,6 +31,7 @@ import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.Order;
import org.springframework.session.ExpiringSession;
import org.springframework.session.Session;
@@ -58,6 +60,7 @@ import org.springframework.session.SessionRepository;
* to ensure the session is overridden and persisted properly.
* </p>
*
* @param <S> the {@link ExpiringSession} type.
* @since 1.0
* @author Rob Winch
*/
@@ -67,8 +70,14 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
private static final Log SESSION_LOGGER = LogFactory.getLog(SESSION_LOGGER_NAME);
/**
* The session repository request attribute name.
*/
public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class.getName();
/**
* The default filter order.
*/
public static final int DEFAULT_ORDER = Integer.MIN_VALUE + 50;
private final SessionRepository<S> sessionRepository;
@@ -78,12 +87,12 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy();
/**
* Creates a new instance
* Creates a new instance.
*
* @param sessionRepository the <code>SessionRepository</code> to use. Cannot be null.
*/
public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {
if(sessionRepository == null) {
if (sessionRepository == null) {
throw new IllegalArgumentException("sessionRepository cannot be null");
}
this.sessionRepository = sessionRepository;
@@ -95,7 +104,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
* @param httpSessionStrategy the {@link HttpSessionStrategy} to use. Cannot be null.
*/
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
if(httpSessionStrategy == null) {
if (httpSessionStrategy == null) {
throw new IllegalArgumentException("httpSessionStrategy cannot be null");
}
this.httpSessionStrategy = new MultiHttpSessionStrategyAdapter(httpSessionStrategy);
@@ -107,24 +116,25 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
* @param httpSessionStrategy the {@link MultiHttpSessionStrategy} to use. Cannot be null.
*/
public void setHttpSessionStrategy(MultiHttpSessionStrategy httpSessionStrategy) {
if(httpSessionStrategy == null) {
if (httpSessionStrategy == null) {
throw new IllegalArgumentException("httpSessionStrategy cannot be null");
}
this.httpSessionStrategy = httpSessionStrategy;
}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository);
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response, servletContext);
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,response);
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response, this.servletContext);
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest, response);
HttpServletRequest strategyRequest = httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);
HttpServletResponse strategyResponse = httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);
HttpServletRequest strategyRequest = this.httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);
HttpServletResponse strategyResponse = this.httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);
try {
filterChain.doFilter(strategyRequest, strategyResponse);
} finally {
}
finally {
wrappedRequest.commitSession();
}
}
@@ -144,11 +154,13 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
private final SessionRepositoryRequestWrapper request;
/**
* Create a new {@link SessionRepositoryResponseWrapper}.
* @param request the request to be wrapped
* @param response the response to be wrapped
*/
public SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request, HttpServletResponse response) {
SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request, HttpServletResponse response) {
super(response);
if(request == null) {
if (request == null) {
throw new IllegalArgumentException("request cannot be null");
}
this.request = request;
@@ -156,7 +168,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
@Override
protected void onResponseCommitted() {
request.commitSession();
this.request.commitSession();
}
}
@@ -185,29 +197,31 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
*/
private void commitSession() {
HttpSessionWrapper wrappedSession = getCurrentSession();
if(wrappedSession == null) {
if(isInvalidateClientSession()) {
httpSessionStrategy.onInvalidateSession(this, response);
if (wrappedSession == null) {
if (isInvalidateClientSession()) {
SessionRepositoryFilter.this.httpSessionStrategy.onInvalidateSession(this, this.response);
}
} else {
}
else {
S session = wrappedSession.getSession();
sessionRepository.save(session);
if(!isRequestedSessionIdValid() || !session.getId().equals(getRequestedSessionId())) {
httpSessionStrategy.onNewSession(session, this, response);
SessionRepositoryFilter.this.sessionRepository.save(session);
if (!isRequestedSessionIdValid() || !session.getId().equals(getRequestedSessionId())) {
SessionRepositoryFilter.this.httpSessionStrategy.onNewSession(session, this, this.response);
}
}
}
@SuppressWarnings("unchecked")
private HttpSessionWrapper getCurrentSession() {
return (HttpSessionWrapper) getAttribute(CURRENT_SESSION_ATTR);
return (HttpSessionWrapper) getAttribute(this.CURRENT_SESSION_ATTR);
}
private void setCurrentSession(HttpSessionWrapper currentSession) {
if(currentSession == null) {
removeAttribute(CURRENT_SESSION_ATTR);
} else {
setAttribute(CURRENT_SESSION_ATTR, currentSession);
if (currentSession == null) {
removeAttribute(this.CURRENT_SESSION_ATTR);
}
else {
setAttribute(this.CURRENT_SESSION_ATTR, currentSession);
}
}
@@ -215,21 +229,21 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
public String changeSessionId() {
HttpSession session = getSession(false);
if(session == null) {
if (session == null) {
throw new IllegalStateException("Cannot change session ID. There is no session associated with this request.");
}
// eagerly get session attributes in case implementation lazily loads them
Map<String,Object> attrs = new HashMap<String,Object>();
Map<String, Object> attrs = new HashMap<String, Object>();
Enumeration<String> iAttrNames = session.getAttributeNames();
while(iAttrNames.hasMoreElements()) {
while (iAttrNames.hasMoreElements()) {
String attrName = iAttrNames.nextElement();
Object value = session.getAttribute(attrName);
attrs.put(attrName, value);
}
sessionRepository.delete(session.getId());
SessionRepositoryFilter.this.sessionRepository.delete(session.getId());
HttpSessionWrapper original = getCurrentSession();
setCurrentSession(null);
@@ -237,7 +251,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
original.setSession(newSession.getSession());
newSession.setMaxInactiveInterval(session.getMaxInactiveInterval());
for(Map.Entry<String, Object> attr : attrs.entrySet()) {
for (Map.Entry<String, Object> attr : attrs.entrySet()) {
String attrName = attr.getKey();
Object attrValue = attr.getValue();
newSession.setAttribute(attrName, attrValue);
@@ -246,29 +260,29 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
}
public boolean isRequestedSessionIdValid() {
if(requestedSessionIdValid == null) {
if (this.requestedSessionIdValid == null) {
String sessionId = getRequestedSessionId();
S session = sessionId == null ? null : getSession(sessionId);
return isRequestedSessionIdValid(session);
}
return requestedSessionIdValid;
return this.requestedSessionIdValid;
}
private boolean isRequestedSessionIdValid(S session) {
if(requestedSessionIdValid == null) {
requestedSessionIdValid = session != null;
if (this.requestedSessionIdValid == null) {
this.requestedSessionIdValid = session != null;
}
return requestedSessionIdValid;
return this.requestedSessionIdValid;
}
private boolean isInvalidateClientSession() {
return getCurrentSession() == null && requestedSessionInvalidated;
return getCurrentSession() == null && this.requestedSessionInvalidated;
}
private S getSession(String sessionId) {
S session = sessionRepository.getSession(sessionId);
if(session == null) {
S session = SessionRepositoryFilter.this.sessionRepository.getSession(sessionId);
if (session == null) {
return null;
}
session.setLastAccessedTime(System.currentTimeMillis());
@@ -278,13 +292,13 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
@Override
public HttpSessionWrapper getSession(boolean create) {
HttpSessionWrapper currentSession = getCurrentSession();
if(currentSession != null) {
if (currentSession != null) {
return currentSession;
}
String requestedSessionId = getRequestedSessionId();
if(requestedSessionId != null) {
if (requestedSessionId != null) {
S session = getSession(requestedSessionId);
if(session != null) {
if (session != null) {
this.requestedSessionIdValid = true;
currentSession = new HttpSessionWrapper(session, getServletContext());
currentSession.setNew(false);
@@ -292,15 +306,15 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
return currentSession;
}
}
if(!create) {
if (!create) {
return null;
}
if(SESSION_LOGGER.isDebugEnabled()) {
if (SESSION_LOGGER.isDebugEnabled()) {
SESSION_LOGGER
.debug("A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for "
+ SESSION_LOGGER_NAME, new RuntimeException("For debugging purposes only (not an error)"));
}
S session = sessionRepository.createSession();
S session = SessionRepositoryFilter.this.sessionRepository.createSession();
session.setLastAccessedTime(System.currentTimeMillis());
currentSession = new HttpSessionWrapper(session, getServletContext());
setCurrentSession(currentSession);
@@ -308,8 +322,8 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
}
public ServletContext getServletContext() {
if(servletContext != null) {
return servletContext;
if (this.servletContext != null) {
return this.servletContext;
}
// Servlet 3.0+
return super.getServletContext();
@@ -322,7 +336,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
@Override
public String getRequestedSessionId() {
return httpSessionStrategy.getRequestedSessionId(this);
return SessionRepositoryFilter.this.httpSessionStrategy.getRequestedSessionId(this);
}
/**
@@ -333,38 +347,45 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
*/
private final class HttpSessionWrapper extends ExpiringSessionHttpSession<S> {
public HttpSessionWrapper(S session, ServletContext servletContext) {
HttpSessionWrapper(S session, ServletContext servletContext) {
super(session, servletContext);
}
public void invalidate() {
super.invalidate();
requestedSessionInvalidated = true;
SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true;
setCurrentSession(null);
sessionRepository.delete(getId());
SessionRepositoryFilter.this.sessionRepository.delete(getId());
}
}
}
/**
* A delegating implementation of {@link MultiHttpSessionStrategy}.
*/
static class MultiHttpSessionStrategyAdapter implements MultiHttpSessionStrategy {
private HttpSessionStrategy delegate;
public MultiHttpSessionStrategyAdapter(HttpSessionStrategy delegate) {
/**
* Create a new {@link MultiHttpSessionStrategyAdapter} instance.
* @param delegate the delegate HTTP session strategy
*/
MultiHttpSessionStrategyAdapter(HttpSessionStrategy delegate) {
this.delegate = delegate;
}
public String getRequestedSessionId(HttpServletRequest request) {
return delegate.getRequestedSessionId(request);
return this.delegate.getRequestedSessionId(request);
}
public void onNewSession(Session session, HttpServletRequest request,
HttpServletResponse response) {
delegate.onNewSession(session, request, response);
this.delegate.onNewSession(session, request, response);
}
public void onInvalidateSession(HttpServletRequest request,
HttpServletResponse response) {
delegate.onInvalidateSession(request, response);
this.delegate.onInvalidateSession(request, response);
}
public HttpServletRequest wrapRequest(HttpServletRequest request,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.socket.config.annotation;
import org.springframework.beans.factory.annotation.Autowired;
@@ -69,11 +70,10 @@ import org.springframework.web.util.UrlPathHelper;
* }
* </code>
*
* @author Rob Winch
* @since 1.0
*
* @param <S>
* the type of ExpiringSession
* @author Rob Winch
* @since 1.0
*/
public abstract class AbstractSessionWebSocketMessageBrokerConfigurer<S extends ExpiringSession> extends AbstractWebSocketMessageBrokerConfigurer {
@@ -90,7 +90,7 @@ public abstract class AbstractSessionWebSocketMessageBrokerConfigurer<S extends
}
public final void registerStompEndpoints(StompEndpointRegistry registry) {
if(registry instanceof WebMvcStompEndpointRegistry) {
if (registry instanceof WebMvcStompEndpointRegistry) {
WebMvcStompEndpointRegistry mvcRegistry = (WebMvcStompEndpointRegistry) registry;
configureStompEndpoints(new SessionStompEndpointRegistry(mvcRegistry, sessionRepositoryInterceptor()));
}
@@ -122,28 +122,31 @@ public abstract class AbstractSessionWebSocketMessageBrokerConfigurer<S extends
@Bean
public WebSocketConnectHandlerDecoratorFactory wsConnectHandlerDecoratorFactory() {
return new WebSocketConnectHandlerDecoratorFactory(eventPublisher);
return new WebSocketConnectHandlerDecoratorFactory(this.eventPublisher);
}
@Bean
@SuppressWarnings("unchecked")
public SessionRepositoryMessageInterceptor<S> sessionRepositoryInterceptor() {
return new SessionRepositoryMessageInterceptor<S>(sessionRepository);
return new SessionRepositoryMessageInterceptor<S>(this.sessionRepository);
}
/**
* A {@link StompEndpointRegistry} that applies {@link HandshakeInterceptor}.
*/
static class SessionStompEndpointRegistry implements StompEndpointRegistry {
private final WebMvcStompEndpointRegistry registry;
private final HandshakeInterceptor interceptor;
public SessionStompEndpointRegistry(WebMvcStompEndpointRegistry registry,
SessionStompEndpointRegistry(WebMvcStompEndpointRegistry registry,
HandshakeInterceptor interceptor) {
this.registry = registry;
this.interceptor = interceptor;
}
public StompWebSocketEndpointRegistration addEndpoint(String... paths) {
StompWebSocketEndpointRegistration endpoints = registry.addEndpoint(paths);
endpoints.addInterceptors(interceptor);
StompWebSocketEndpointRegistration endpoints = this.registry.addEndpoint(paths);
endpoints.addInterceptors(this.interceptor);
return endpoints;
}
@@ -159,4 +162,4 @@ public abstract class AbstractSessionWebSocketMessageBrokerConfigurer<S extends
return this.registry.setErrorHandler(errorHandler);
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.socket.events;
import org.springframework.context.ApplicationEvent;
@@ -42,6 +43,6 @@ public class SessionConnectEvent extends ApplicationEvent {
}
public WebSocketSession getWebSocketSession() {
return webSocketSession;
return this.webSocketSession;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.socket.handler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.session.Session;
@@ -47,7 +49,7 @@ public final class WebSocketConnectHandlerDecoratorFactory implements WebSocketH
private final ApplicationEventPublisher eventPublisher;
/**
* Creates a new instance
* Creates a new instance.
*
* @param eventPublisher the {@link ApplicationEventPublisher} to use. Cannot be null.
*/
@@ -63,7 +65,7 @@ public final class WebSocketConnectHandlerDecoratorFactory implements WebSocketH
private final class SessionWebSocketHandler extends WebSocketHandlerDecorator {
public SessionWebSocketHandler(WebSocketHandler delegate) {
SessionWebSocketHandler(WebSocketHandler delegate) {
super(delegate);
}
@@ -72,12 +74,12 @@ public final class WebSocketConnectHandlerDecoratorFactory implements WebSocketH
throws Exception {
super.afterConnectionEstablished(wsSession);
publishEvent(new SessionConnectEvent(this,wsSession));
publishEvent(new SessionConnectEvent(this, wsSession));
}
private void publishEvent(ApplicationEvent event) {
try {
eventPublisher.publishEvent(event);
WebSocketConnectHandlerDecoratorFactory.this.eventPublisher.publishEvent(event);
}
catch (Throwable ex) {
logger.error("Error publishing " + event + ".", ex);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.socket.handler;
import java.io.IOException;
@@ -22,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
@@ -51,16 +53,18 @@ public final class WebSocketRegistryListener implements ApplicationListener<Appl
static final CloseStatus SESSION_EXPIRED_STATUS = new CloseStatus(CloseStatus.POLICY_VIOLATION.getCode(),
"This connection was established under an authenticated HTTP Session that has expired");
private final ConcurrentHashMap<String,Map<String,WebSocketSession>> httpSessionIdToWsSessions = new ConcurrentHashMap<String,Map<String,WebSocketSession>>();
private final ConcurrentHashMap<String, Map<String, WebSocketSession>> httpSessionIdToWsSessions = new ConcurrentHashMap<String, Map<String, WebSocketSession>>();
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof SessionDestroyedEvent) {
if (event instanceof SessionDestroyedEvent) {
SessionDestroyedEvent e = (SessionDestroyedEvent) event;
closeWsSessions(e.getSessionId());
} else if(event instanceof SessionConnectEvent) {
}
else if (event instanceof SessionConnectEvent) {
SessionConnectEvent e = (SessionConnectEvent) event;
afterConnectionEstablished(e.getWebSocketSession());
} else if(event instanceof SessionDisconnectEvent) {
}
else if (event instanceof SessionDisconnectEvent) {
SessionDisconnectEvent e = (SessionDisconnectEvent) event;
Map<String, Object> sessionAttributes = SimpMessageHeaderAccessor.getSessionAttributes(e.getMessage().getHeaders());
String httpSessionId = sessionAttributes == null ? null : SessionRepositoryMessageInterceptor.getSessionId(sessionAttributes);
@@ -70,7 +74,7 @@ public final class WebSocketRegistryListener implements ApplicationListener<Appl
private void afterConnectionEstablished(WebSocketSession wsSession) {
Principal principal = wsSession.getPrincipal();
if(principal == null) {
if (principal == null) {
return;
}
@@ -84,19 +88,19 @@ public final class WebSocketRegistryListener implements ApplicationListener<Appl
}
private void afterConnectionClosed(String httpSessionId, String wsSessionId) {
if(httpSessionId == null) {
if (httpSessionId == null) {
return;
}
Map<String,WebSocketSession> sessions = httpSessionIdToWsSessions.get(httpSessionId);
if(sessions != null) {
Map<String, WebSocketSession> sessions = this.httpSessionIdToWsSessions.get(httpSessionId);
if (sessions != null) {
boolean result = sessions.remove(wsSessionId) != null;
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Removal of " + wsSessionId + " was " + result);
}
if(sessions.isEmpty()) {
httpSessionIdToWsSessions.remove(httpSessionId);
if(logger.isDebugEnabled()) {
if (sessions.isEmpty()) {
this.httpSessionIdToWsSessions.remove(httpSessionId);
if (logger.isDebugEnabled()) {
logger.debug("Removed the corresponding HTTP Session for " + wsSessionId + " since it contained no WebSocket mappings");
}
}
@@ -104,30 +108,31 @@ public final class WebSocketRegistryListener implements ApplicationListener<Appl
}
private void registerWsSession(String httpSessionId, WebSocketSession wsSession) {
Map<String,WebSocketSession> sessions = httpSessionIdToWsSessions.get(httpSessionId);
if(sessions == null) {
Map<String, WebSocketSession> sessions = this.httpSessionIdToWsSessions.get(httpSessionId);
if (sessions == null) {
sessions =
new ConcurrentHashMap<String,WebSocketSession>();
httpSessionIdToWsSessions.putIfAbsent(httpSessionId, sessions);
sessions = httpSessionIdToWsSessions.get(httpSessionId);
new ConcurrentHashMap<String, WebSocketSession>();
this.httpSessionIdToWsSessions.putIfAbsent(httpSessionId, sessions);
sessions = this.httpSessionIdToWsSessions.get(httpSessionId);
}
sessions.put(wsSession.getId(), wsSession);
}
private void closeWsSessions(String httpSessionId) {
Map<String,WebSocketSession> sessionsToClose = httpSessionIdToWsSessions.remove(httpSessionId);
if(sessionsToClose == null) {
Map<String, WebSocketSession> sessionsToClose = this.httpSessionIdToWsSessions.remove(httpSessionId);
if (sessionsToClose == null) {
return;
}
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Closing WebSocket connections associated to expired HTTP Session " + httpSessionId);
}
for(WebSocketSession toClose : sessionsToClose.values()) {
for (WebSocketSession toClose : sessionsToClose.values()) {
try {
toClose.close(SESSION_EXPIRED_STATUS);
} catch (IOException e) {
logger.debug("Failed to close WebSocketSession (this is nothing to worry about but for debugging only)",e);
}
catch (IOException e) {
logger.debug("Failed to close WebSocketSession (this is nothing to worry about but for debugging only)", e);
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.web.socket.server;
import java.util.EnumSet;
@@ -62,6 +63,7 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
* .
* </p>
*
* @param <S> the {@link ExpiringSession} type
* @author Rob Winch
* @since 1.0
*/
@@ -75,7 +77,7 @@ public final class SessionRepositoryMessageInterceptor<S extends ExpiringSession
private Set<SimpMessageType> matchingMessageTypes;
/**
* Creates a new instance
* Creates a new instance.
*
* @param sessionRepository the {@link SessionRepository} to use. Cannot be null.
*/
@@ -105,27 +107,27 @@ public final class SessionRepositoryMessageInterceptor<S extends ExpiringSession
* {@link Session}
*/
public void setMatchingMessageTypes(Set<SimpMessageType> matchingMessageTypes) {
Assert.notEmpty(matchingMessageTypes,"matchingMessageTypes cannot be null or empty");
Assert.notEmpty(matchingMessageTypes, "matchingMessageTypes cannot be null or empty");
this.matchingMessageTypes = matchingMessageTypes;
}
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
if(message == null) {
if (message == null) {
return message;
}
SimpMessageType messageType = SimpMessageHeaderAccessor.getMessageType(message.getHeaders());
if(!this.matchingMessageTypes.contains(messageType)) {
if (!this.matchingMessageTypes.contains(messageType)) {
return super.preSend(message, channel);
}
Map<String, Object> sessionHeaders = SimpMessageHeaderAccessor.getSessionAttributes(message.getHeaders());
String sessionId = sessionHeaders == null ? null : (String) sessionHeaders.get(SPRING_SESSION_ID_ATTR_NAME);
if (sessionId != null) {
S session = sessionRepository.getSession(sessionId);
S session = this.sessionRepository.getSession(sessionId);
if (session != null) {
// update the last accessed time
session.setLastAccessedTime(System.currentTimeMillis());
sessionRepository.save(session);
this.sessionRepository.save(session);
}
}
return super.preSend(message, channel);
@@ -156,4 +158,4 @@ public final class SessionRepositoryMessageInterceptor<S extends ExpiringSession
public static void setSessionId(Map<String, Object> attributes, String sessionId) {
attributes.put(SPRING_SESSION_ID_ATTR_NAME, sessionId);
}
}
}