From 308bf0e6b7b3479ab479843006a2becf1a7af387 Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 6 Dec 2018 01:04:55 -0800 Subject: [PATCH] Introduce usingDataSerialization boolean flag fixing bug when DataSerializer is not the DataSerializableSessionSerializer provided by SSDG. Rename exposeSpringSessionGemFireConfigurationAsProperties() to exposeSpringSessionGemFireConfiguration(). --- ...pSessionConfigurationIntegrationTests.java | 192 ++++++++++++++++++ .../http/GemFireHttpSessionConfiguration.java | 31 ++- .../GemFireHttpSessionConfigurationTests.java | 11 +- 3 files changed, 226 insertions(+), 8 deletions(-) create mode 100644 spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationIntegrationTests.java diff --git a/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationIntegrationTests.java b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationIntegrationTests.java new file mode 100644 index 0000000..5442098 --- /dev/null +++ b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationIntegrationTests.java @@ -0,0 +1,192 @@ +/* + * Copyright 2018 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 + * + * 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.data.gemfire.config.annotation.web.http; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; + +import java.io.DataInput; +import java.io.DataOutput; +import java.util.Arrays; + +import org.junit.Test; + +import org.apache.geode.DataSerializer; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.internal.InternalDataSerializer; + +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.config.annotation.ClientCacheApplication; +import org.springframework.data.gemfire.tests.integration.SpringApplicationContextIntegrationTestsSupport; +import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects; +import org.springframework.session.data.gemfire.serialization.SessionSerializer; +import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer; +import org.springframework.session.data.gemfire.serialization.data.provider.DataSerializableSessionSerializer; +import org.springframework.session.data.gemfire.serialization.pdx.support.PdxSerializerSessionSerializerAdapter; + +/** + * The GemFireHttpSessionConfigurationIntegrationTests class... + * + * @author John Blum + * @since 1.0.0 + */ +@SuppressWarnings("unused") +public class GemFireHttpSessionConfigurationIntegrationTests extends SpringApplicationContextIntegrationTestsSupport { + + private void assertDataSerializerRegistered(DataSerializer dataSerializer) { + assertDataSerializerRegistered(dataSerializer.getClass()); + } + + private void assertDataSerializerRegistered(Class dataSerializerType) { + + assertThat(Arrays.stream(nullSafeArray(InternalDataSerializer.getSerializers(), DataSerializer.class)) + .map(Object::getClass) + .filter(dataSerializerType::isAssignableFrom) + .findFirst() + .orElse(null)).isNotNull(); + } + + private void testUsesDataSerialization(Class expectedDataSerializerType) { + + GemFireHttpSessionConfiguration configuration = + getApplicationContext().getBean(GemFireHttpSessionConfiguration.class); + + assertThat(configuration).isNotNull(); + assertThat(configuration.isUsingDataSerialization()).isTrue(); + + GemFireCache gemfireCache = getApplicationContext().getBean(GemFireCache.class); + + assertThat(gemfireCache).isNotNull(); + assertThat(gemfireCache.getPdxSerializer()).isNull(); + + DataSerializer dataSerializer = + getApplicationContext().getBean(configuration.getSessionSerializerBeanName(), expectedDataSerializerType); + + assertThat(dataSerializer).isInstanceOf(expectedDataSerializerType); + assertDataSerializerRegistered(dataSerializer); + } + + @Test + public void usesDataSerializationWhenDataSerializableSessionSerializerConfigured() { + + newApplicationContext(DataSerializableSessionSerializerConfiguration.class); + + testUsesDataSerialization(DataSerializableSessionSerializer.class); + } + + @Test + public void usesDataSerializationWhenTestDataSerializerConfigured() { + + newApplicationContext(TestDataSerializerConfiguration.class); + + testUsesDataSerialization(TestDataSerializer.class); + } + + @Test + public void notUsingDataSerializationWhenPdxConfigured() { + + newApplicationContext(TestSessionSerializerConfiguration.class); + + GemFireHttpSessionConfiguration configuration = + getApplicationContext().getBean(GemFireHttpSessionConfiguration.class); + + assertThat(configuration).isNotNull(); + assertThat(configuration.isUsingDataSerialization()).isFalse(); + + GemFireCache gemfireCache = getApplicationContext().getBean(GemFireCache.class); + + SessionSerializer testSessionSerializer = + getApplicationContext().getBean("TestSessionSerializer", SessionSerializer.class); + + assertThat(gemfireCache).isNotNull(); + assertThat(gemfireCache.getPdxSerializer()).isInstanceOf(PdxSerializerSessionSerializerAdapter.class); + assertThat(((PdxSerializerSessionSerializerAdapter) gemfireCache.getPdxSerializer()).getSessionSerializer()) + .isEqualTo(testSessionSerializer); + + assertThat(Arrays.stream(nullSafeArray(InternalDataSerializer.getSerializers(), DataSerializer.class)) + .filter(testSessionSerializer::equals) + .findAny() + .orElse(null)).isNull(); + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableGemFireHttpSession( + poolName = "DEFAULT", + sessionSerializerBeanName = GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME + ) + static class DataSerializableSessionSerializerConfiguration { } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableGemFireHttpSession(poolName = "DEFAULT", sessionSerializerBeanName = "TestDataSerializer") + static class TestDataSerializerConfiguration { + + @Bean("TestDataSerializer") + DataSerializer testDataSerializer() { + return new TestDataSerializer(); + } + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableGemFireHttpSession(poolName = "DEFAULT", sessionSerializerBeanName = "TestSessionSerializer") + static class TestSessionSerializerConfiguration { + + @Bean("TestSessionSerializer") + SessionSerializer testSessionSerializer() { + return mock(SessionSerializer.class); + } + } + + static class TestDataSerializer extends AbstractDataSerializableSessionSerializer { + + @Override + public Class[] getSupportedClasses() { + return new Class[] { Object.class }; + } + + @Override + public void serialize(Object session, DataOutput dataOutput) { + throw new UnsupportedOperationException("Not Implemented"); + } + + @Override + public Object deserialize(DataInput dataInput) { + throw new UnsupportedOperationException("Not Implemented"); + } + } + + static class TestSessionSerializer implements SessionSerializer { + + @Override + public void serialize(Object session, DataOutput dataOutput) { + throw new UnsupportedOperationException("Not Implemented"); + } + + @Override + public Object deserialize(DataInput dataInput) { + throw new UnsupportedOperationException("Not Implemented"); + } + + @Override + public boolean canSerialize(Class type) { + return false; + } + } +} diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java index 9d1d2a4..38247c2 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java @@ -146,6 +146,12 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC */ public static final boolean DEFAULT_EXPOSE_CONFIGURATION_AS_PROPERTIES = false; + /** + * Indicates whether to employ Apache Geode/Pivotal's DataSerialization framework + * for {@link Session} de/serialization. + */ + public static final boolean DEFAULT_USE_DATA_SERIALIZATION = false; + /** * Default maximum interval in seconds in which a {@link Session} can remain inactive before it expires. */ @@ -233,6 +239,7 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC public static final String[] DEFAULT_INDEXABLE_SESSION_ATTRIBUTES = {}; private boolean exposeConfigurationAsProperties = DEFAULT_EXPOSE_CONFIGURATION_AS_PROPERTIES; + private boolean usingDataSerialization = DEFAULT_USE_DATA_SERIALIZATION; private int maxInactiveIntervalInSeconds = DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS; @@ -538,6 +545,17 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC .orElse(DEFAULT_SESSION_SERIALIZER_BEAN_NAME); } + /** + * Set whether to use Apache Geode / Pivotal GemFire's DataSerialization framework + * for {@link Session} de/serialization. + * + * @param useDataSerialization boolean value indicating whether to use Apache Geode + * / Pivotal GemFire's DataSerialization framework for {@link Session} de/serialization. + */ + private void setUseDataSerialization(boolean useDataSerialization) { + this.usingDataSerialization = useDataSerialization; + } + /** * Determine whether the configured serialization strategy is using Apache Geode / Pivotal GemFire's * DataSerialization framework. @@ -547,7 +565,9 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC * @see #getSessionSerializerBeanName() */ protected boolean isUsingDataSerialization() { - return SESSION_DATA_SERIALIZER_BEAN_NAME.equals(getSessionSerializerBeanName()); + + return this.usingDataSerialization + || SESSION_DATA_SERIALIZER_BEAN_NAME.equals(getSessionSerializerBeanName()); } /** @@ -560,7 +580,7 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC * this {@link Configuration} class. * @see org.springframework.core.type.AnnotationMetadata * @see #applySpringSessionGemFireConfigurer() - * @see #exposeSpringSessionGemFireConfigurationAsProperties() + * @see #exposeSpringSessionGemFireConfiguration() */ public void setImportMetadata(AnnotationMetadata importMetadata) { @@ -585,7 +605,7 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC // Expose configuration as {@link Properties} in the Spring {@link Environment} // if {@link EnableGemFireHttpSession#exposeConfigurationAsProperties} is set to {@literal true}. - exposeSpringSessionGemFireConfigurationAsProperties(); + exposeSpringSessionGemFireConfiguration(); } private void configureClientRegionShortcut(AnnotationAttributes enableGemFireHttpSessionAttributes) { @@ -786,7 +806,7 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC * * @see #isExposeConfigurationAsProperties() */ - void exposeSpringSessionGemFireConfigurationAsProperties() { + void exposeSpringSessionGemFireConfiguration() { if (isExposeConfigurationAsProperties()) { @@ -907,12 +927,15 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC private void configureSerialization(CacheFactoryBean cacheFactoryBean, SessionSerializer sessionSerializer) { if (sessionSerializer instanceof DataSerializer) { + if (sessionSerializer instanceof DataSerializableSessionSerializer) { DataSerializableSessionSerializer.register(); } else { DataSerializer.register(sessionSerializer.getClass()); } + + setUseDataSerialization(true); } else if (sessionSerializer instanceof PdxSerializer) { cacheFactoryBean.setPdxSerializer(ComposablePdxSerializer.compose( diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTests.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTests.java index 6bfecca..77b6931 100644 --- a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTests.java +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTests.java @@ -99,8 +99,11 @@ public class GemFireHttpSessionConfigurationTests { private T getField(Object obj, String fieldName) { try { + Field field = resolveField(obj, fieldName); + field.setAccessible(true); + return (T) field.get(obj); } catch (NoSuchFieldException cause) { @@ -538,7 +541,7 @@ public class GemFireHttpSessionConfigurationTests { this.gemfireConfiguration.setSessionRegionName("Sessions"); this.gemfireConfiguration.setSessionSerializerBeanName("TestSessionSerializer"); this.gemfireConfiguration.setExposeConfigurationAsProperties(true); - this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties(); + this.gemfireConfiguration.exposeSpringSessionGemFireConfiguration(); PropertySource springSessionGemFirePropertySource = environment.getPropertySources() .get(GemFireHttpSessionConfiguration.SPRING_SESSION_GEMFIRE_PROPERTY_SOURCE); @@ -593,7 +596,7 @@ public class GemFireHttpSessionConfigurationTests { this.gemfireConfiguration.setEnvironment(null); this.gemfireConfiguration.setExposeConfigurationAsProperties(true); - this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties(); + this.gemfireConfiguration.exposeSpringSessionGemFireConfiguration(); verify(this.gemfireConfiguration, never()).getClientRegionShortcut(); verify(this.gemfireConfiguration, times(1)).getEnvironment(); @@ -614,7 +617,7 @@ public class GemFireHttpSessionConfigurationTests { this.gemfireConfiguration.setEnvironment(mockEnvironment); this.gemfireConfiguration.setExposeConfigurationAsProperties(false); - this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties(); + this.gemfireConfiguration.exposeSpringSessionGemFireConfiguration(); verify(this.gemfireConfiguration, never()).getClientRegionShortcut(); verify(this.gemfireConfiguration, never()).getEnvironment(); @@ -636,7 +639,7 @@ public class GemFireHttpSessionConfigurationTests { this.gemfireConfiguration.setEnvironment(mockEnvironment); this.gemfireConfiguration.setExposeConfigurationAsProperties(true); - this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties(); + this.gemfireConfiguration.exposeSpringSessionGemFireConfiguration(); verify(this.gemfireConfiguration, never()).getClientRegionShortcut(); verify(this.gemfireConfiguration, times(1)).getEnvironment();