Configure the serialization strategy from the declared, defined and registered SessionSerializer bean.
Resolves Issue #2.
This commit is contained in:
@@ -93,6 +93,8 @@ import org.apache.commons.logging.LogFactory;
|
||||
public abstract class AbstractGemFireOperationsSessionRepository extends CacheListenerAdapter<Object, Session>
|
||||
implements ApplicationEventPublisherAware, FindByIndexNameSessionRepository<Session>, InitializingBean {
|
||||
|
||||
private boolean usingDataSerialization = false;
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher = new ApplicationEventPublisher() {
|
||||
|
||||
public void publishEvent(ApplicationEvent event) {
|
||||
@@ -238,6 +240,24 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
.map(Long::intValue).orElse(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a condition indicating whether the DataSerialization framework has been configured.
|
||||
*
|
||||
* @param useDataSerialization boolean indicating whether the DataSerialization framework has been configured.
|
||||
*/
|
||||
public void setUseDataSerialization(boolean useDataSerialization) {
|
||||
this.usingDataSerialization = useDataSerialization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the DataSerialization framework has been configured.
|
||||
*
|
||||
* @return a boolean indicating whether the DataSerialization framework has been configured.
|
||||
*/
|
||||
protected boolean isUsingDataSerialization() {
|
||||
return this.usingDataSerialization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the {@link GemfireOperations template} used to perform data access operations
|
||||
* and other interactions on the cache {@link Region} backing this {@link SessionRepository}.
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package org.springframework.session.data.gemfire.config.annotation.web.http;
|
||||
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.geode.DataSerializer;
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.ExpirationAction;
|
||||
import org.apache.geode.cache.ExpirationAttributes;
|
||||
@@ -29,21 +32,33 @@ import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
import org.apache.geode.pdx.PdxSerializer;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.GemfireOperations;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.IndexFactoryBean;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
|
||||
import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer;
|
||||
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
@@ -55,7 +70,10 @@ import org.springframework.session.data.gemfire.config.annotation.web.http.suppo
|
||||
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
|
||||
import org.springframework.session.data.gemfire.serialization.data.provider.DataSerializableSessionSerializer;
|
||||
import org.springframework.session.data.gemfire.serialization.pdx.provider.PdxSerializableSessionSerializer;
|
||||
import org.springframework.session.data.gemfire.serialization.pdx.support.ComposablePdxSerializer;
|
||||
import org.springframework.session.data.gemfire.serialization.pdx.support.PdxSerializerSessionSerializerAdapter;
|
||||
import org.springframework.session.data.gemfire.support.GemFireUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -134,9 +152,13 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
*/
|
||||
public static final String SESSION_DATA_SERIALIZER_BEAN_NAME = "SessionDataSerializer";
|
||||
public static final String SESSION_PDX_SERIALIZER_BEAN_NAME = "SessionPdxSerializer";
|
||||
|
||||
public static final String SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME =
|
||||
"spring.session.data.geode.serializer.qualifier";
|
||||
|
||||
public static final String SESSION_SERIALIZER_REGISTERED_ALIAS =
|
||||
"org.springframework.session.data.geode.serializer.registeredAlias";
|
||||
|
||||
public static final String DEFAULT_SESSION_SERIALIZER_BEAN_NAME = SESSION_DATA_SERIALIZER_BEAN_NAME;
|
||||
|
||||
/**
|
||||
@@ -146,6 +168,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
|
||||
private int maxInactiveIntervalInSeconds = DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private ClientRegionShortcut clientRegionShortcut = DEFAULT_CLIENT_REGION_SHORTCUT;
|
||||
@@ -160,6 +184,17 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
|
||||
private String[] indexableSessionAttributes = DEFAULT_INDEXABLE_SESSION_ATTRIBUTES;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
super.setApplicationContext(applicationContext);
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
return Optional.ofNullable(this.applicationContext)
|
||||
.orElseThrow(() -> newIllegalStateException("The ApplicationContext was not properly configured"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the {@link ClassLoader} used by the Spring container to load bean class types.
|
||||
*
|
||||
@@ -171,6 +206,17 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
|
||||
protected ConfigurableBeanFactory getBeanFactory() {
|
||||
|
||||
ApplicationContext applicationContext = getApplicationContext();
|
||||
|
||||
return Optional.of(applicationContext)
|
||||
.filter(it -> it instanceof ConfigurableApplicationContext)
|
||||
.map(it -> ((ConfigurableApplicationContext) it).getBeanFactory())
|
||||
.orElseThrow(() -> newIllegalStateException("Unable to resolve a reference to a [%1$s] from a [%2$s]",
|
||||
ConfigurableBeanFactory.class.getName(), ObjectUtils.nullSafeClassName(applicationContext)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link ClassLoader} used by the Spring container to load bean class types.
|
||||
*
|
||||
@@ -362,6 +408,10 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
.orElse(DEFAULT_SESSION_SERIALIZER_BEAN_NAME);
|
||||
}
|
||||
|
||||
protected boolean isUsingDataSerialization() {
|
||||
return SESSION_DATA_SERIALIZER_BEAN_NAME.equals(getSessionSerializerBeanName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback with the {@link AnnotationMetadata} of the class containing {@link Import @Import} annotation
|
||||
* that imported this {@link Configuration @Configuration} class.
|
||||
@@ -396,6 +446,49 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
enableGemFireHttpSessionAttributes.getString("sessionSerializerBeanName"));
|
||||
|
||||
System.setProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, getSessionSerializerBeanName());
|
||||
|
||||
getBeanFactory().registerAlias(getSessionSerializerBeanName(), SESSION_SERIALIZER_REGISTERED_ALIAS);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ClientCacheConfigurer sessionClientCacheConfigurer(
|
||||
@Qualifier(SESSION_SERIALIZER_REGISTERED_ALIAS) SessionSerializer sessionSerializer) {
|
||||
|
||||
return (beanName, clientCacheFactoryBean) -> configureSerialization(clientCacheFactoryBean, sessionSerializer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PeerCacheConfigurer sessionPeerCacheConfigurer(
|
||||
@Qualifier(SESSION_SERIALIZER_REGISTERED_ALIAS) SessionSerializer sessionSerializer) {
|
||||
|
||||
return (beanName, cacheFactoryBean) -> configureSerialization(cacheFactoryBean, sessionSerializer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void configureSerialization(CacheFactoryBean cacheFactoryBean, SessionSerializer sessionSerializer) {
|
||||
|
||||
if (sessionSerializer instanceof DataSerializer) {
|
||||
if (sessionSerializer instanceof DataSerializableSessionSerializer) {
|
||||
DataSerializableSessionSerializer.register();
|
||||
}
|
||||
else {
|
||||
DataSerializer.register(sessionSerializer.getClass());
|
||||
}
|
||||
}
|
||||
else if (sessionSerializer instanceof PdxSerializer) {
|
||||
cacheFactoryBean.setPdxSerializer(ComposablePdxSerializer.compose(
|
||||
(PdxSerializer) sessionSerializer, cacheFactoryBean.getPdxSerializer()));
|
||||
}
|
||||
else {
|
||||
// TODO add more intelligence to figure out what type of serializer has been configured
|
||||
// (e.g. PDX or DataSerialization based serializers)
|
||||
Optional.ofNullable(sessionSerializer)
|
||||
.ifPresent(serializer ->
|
||||
cacheFactoryBean.setPdxSerializer(ComposablePdxSerializer.compose(
|
||||
new PdxSerializerSessionSerializerAdapter<>(sessionSerializer),
|
||||
cacheFactoryBean.getPdxSerializer()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,6 +510,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
new GemFireOperationsSessionRepository(gemfireOperations);
|
||||
|
||||
sessionRepository.setMaxInactiveIntervalInSeconds(getMaxInactiveIntervalInSeconds());
|
||||
sessionRepository.setUseDataSerialization(isUsingDataSerialization());
|
||||
|
||||
return sessionRepository;
|
||||
}
|
||||
@@ -524,11 +618,13 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
}
|
||||
|
||||
@Bean(SESSION_DATA_SERIALIZER_BEAN_NAME)
|
||||
@Conditional(DataSerializableSessionSerializerCondition.class)
|
||||
public Object sessionDataSerializer() {
|
||||
return new PdxSerializableSessionSerializer();
|
||||
}
|
||||
|
||||
@Bean(SESSION_PDX_SERIALIZER_BEAN_NAME)
|
||||
@Conditional(PdxSerializableSessionSerializerCondition.class)
|
||||
public Object sessionPdxSerializer() {
|
||||
return new DataSerializableSessionSerializer();
|
||||
}
|
||||
@@ -582,4 +678,22 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
|
||||
return sessionAttributesIndex;
|
||||
}
|
||||
|
||||
public static class DataSerializableSessionSerializerCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return SESSION_DATA_SERIALIZER_BEAN_NAME
|
||||
.equals(context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
public static class PdxSerializableSessionSerializerCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return SESSION_PDX_SERIALIZER_BEAN_NAME
|
||||
.equals(context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user