You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2022/02/10 18:54:31 UTC
[geode] branch support/1.15 updated: GEODE-9980: Improve error handling of serial filters (#7355)
This is an automated email from the ASF dual-hosted git repository.
klund pushed a commit to branch support/1.15
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/support/1.15 by this push:
new 6ecdce0 GEODE-9980: Improve error handling of serial filters (#7355)
6ecdce0 is described below
commit 6ecdce0d9ef9040f3bbb90c8ea4ff5eb99d712fc
Author: Kirk Lund <kl...@apache.org>
AuthorDate: Thu Feb 10 10:53:21 2022 -0800
GEODE-9980: Improve error handling of serial filters (#7355)
Improves the error handling of serial filter configuration and
filtering. The API throws a runtime exception wrapping any thrown
exceptions.
When geode.enableGlobalSerialFilter is FALSE:
* Startup succeeds without throwing any exceptions even if an older
version of Java throws "java.lang.ClassNotFoundException
sun.misc.ObjectInputFilter".
When geode.enableGlobalSerialFilter is TRUE:
* Startup fails by throwing an exception when configuration of serial
filter fails for any reason.
Renames ObjectInputFilter to avoid confusion with the Java interface of
the same name.
Fixes a bug found in ReflectiveFacadeGlobalSerialFilterTest which
resulted in configuring a non-mocked process-wide serial filter that
polluted the JVM for all later tests.
Fixes other minor details in LocatorLauncher, InternalDataSerializer
and various related tests.
(cherry picked from commit ce57e9fd2b8b644cadc469209e12e4fbd281e0d9)
---
.../filter/SerialFilterAssertions.java | 30 +++---
.../apache/geode/distributed/LocatorLauncher.java | 16 ++-
.../apache/geode/distributed/ServerLauncher.java | 16 ++-
.../geode/internal/InternalDataSerializer.java | 29 ++++--
.../geode/management/internal/ManagementAgent.java | 7 +-
.../geode/distributed/LocatorLauncherTest.java | 2 +-
...ationWhenFilterIsAlreadySetIntegrationTest.java | 53 ++++++++++
...enObjectInputFilterNotFoundIntegrationTest.java | 108 ++++++++++++++++++++
...nputFilterApiSetFilterBlankIntegrationTest.java | 1 -
....java => FilterAlreadyConfiguredException.java} | 22 +++--
.../serialization/filter/FilterConfiguration.java | 2 +-
.../serialization/filter/GlobalSerialFilter.java | 5 +-
.../filter/GlobalSerialFilterConfiguration.java | 86 +++++++---------
.../filter/JmxSerialFilterConfiguration.java | 15 +--
...nputFilter.java => NullStreamSerialFilter.java} | 4 +-
.../filter/ObjectInputFilterInvocationHandler.java | 109 +++++++++++++++++++++
.../filter/ReflectiveFacadeGlobalSerialFilter.java | 43 ++++++--
.../ReflectiveFacadeGlobalSerialFilterFactory.java | 20 ++--
.../ReflectiveFacadeObjectInputFilterFactory.java | 61 ------------
...ava => ReflectiveFacadeStreamSerialFilter.java} | 49 +++++++--
...ReflectiveFacadeStreamSerialFilterFactory.java} | 35 +++----
.../filter/ReflectiveObjectInputFilterApi.java | 59 +++--------
...ectInputFilter.java => StreamSerialFilter.java} | 7 +-
...Factory.java => StreamSerialFilterFactory.java} | 4 +-
...ertyGlobalSerialFilterConfigurationFactory.java | 24 ++++-
....java => UnableToSetSerialFilterException.java} | 22 +++--
...anctioned-geode-serialization-serializables.txt | 2 +
.../GlobalSerialFilterConfigurationTest.java | 84 ++++++++++++----
.../JmxSerialFilterConfigurationFactoryTest.java | 9 ++
.../filter/JmxSerialFilterConfigurationTest.java | 50 ++++++----
.../filter/NullObjectInputFilterTest.java | 4 +-
.../ObjectInputFilterInvocationHandlerTest.java | 97 ++++++++++++++++++
...lectiveFacadeGlobalSerialFilterFactoryTest.java | 65 ++++++------
.../ReflectiveFacadeGlobalSerialFilterTest.java | 88 ++++++++++++++---
...flectiveFacadeObjectInputFilterFactoryTest.java | 12 +--
.../ReflectiveFacadeObjectInputFilterTest.java | 77 ++++++++++-----
.../ReflectiveObjectInputFilterApiFactoryTest.java | 9 ++
.../filter/ReflectiveObjectInputFilterApiTest.java | 11 ++-
.../filter/SerialFilterAssertions.java | 53 +++++-----
...GlobalSerialFilterConfigurationFactoryTest.java | 101 ++++++++++++++++---
...rtyJmxSerialFilterConfigurationFactoryTest.java | 12 ++-
41 files changed, 1068 insertions(+), 435 deletions(-)
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
index b6d552a..8432e7d 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
@@ -30,35 +30,29 @@ public class SerialFilterAssertions {
public static void assertThatSerialFilterIsNull()
throws InvocationTargetException, IllegalAccessException {
- boolean exists = API.getSerialFilter() != null;
- assertThat(exists)
- .as("ObjectInputFilter$Config.getSerialFilter() is null")
- .isFalse();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isNull();
}
public static void assertThatSerialFilterIsNotNull()
throws InvocationTargetException, IllegalAccessException {
- boolean exists = API.getSerialFilter() != null;
- assertThat(exists)
- .as("ObjectInputFilter$Config.getSerialFilter() is not null")
- .isTrue();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isNotNull();
}
public static void assertThatSerialFilterIsSameAs(Object objectInputFilter)
throws InvocationTargetException, IllegalAccessException {
- Object currentFilter = API.getSerialFilter();
- boolean sameIdentity = currentFilter == objectInputFilter;
- assertThat(sameIdentity)
- .as("ObjectInputFilter$Config.getSerialFilter() is same as parameter")
- .isTrue();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isSameAs(objectInputFilter);
}
public static void assertThatSerialFilterIsNotSameAs(Object objectInputFilter)
throws InvocationTargetException, IllegalAccessException {
- Object currentFilter = API.getSerialFilter();
- boolean sameIdentity = currentFilter == objectInputFilter;
- assertThat(sameIdentity)
- .as("ObjectInputFilter$Config.getSerialFilter() is same as parameter")
- .isFalse();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isNotSameAs(objectInputFilter);
}
}
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
index b873d14..d13eabf 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
@@ -90,6 +90,7 @@ import org.apache.geode.internal.process.ProcessUtils;
import org.apache.geode.internal.process.UnableToControlProcessException;
import org.apache.geode.internal.security.SecurableCommunicationChannel;
import org.apache.geode.internal.serialization.filter.SystemPropertyGlobalSerialFilterConfigurationFactory;
+import org.apache.geode.internal.serialization.filter.UnableToSetSerialFilterException;
import org.apache.geode.lang.AttachAPINotFoundException;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.management.internal.util.HostUtils;
@@ -716,10 +717,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
if (isStartable()) {
INSTANCE.compareAndSet(null, this);
- boolean serializationFilterConfigured =
- new SystemPropertyGlobalSerialFilterConfigurationFactory()
- .create(new DistributedSerializableObjectConfig(getDistributedSystemProperties()))
- .configure();
+ boolean serializationFilterConfigured = configureGlobalSerialFilterIfEnabled();
try {
this.process =
@@ -785,6 +783,16 @@ public class LocatorLauncher extends AbstractLauncher<String> {
}
}
+ private boolean configureGlobalSerialFilterIfEnabled() {
+ try {
+ return new SystemPropertyGlobalSerialFilterConfigurationFactory()
+ .create(new DistributedSerializableObjectConfig(getDistributedSystemProperties()))
+ .configure();
+ } catch (UnableToSetSerialFilterException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
protected Properties getDistributedSystemProperties() {
return super.getDistributedSystemProperties(getProperties());
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
index 6adcc7d..2dfd8c0 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
@@ -96,6 +96,7 @@ import org.apache.geode.internal.process.ProcessLauncherContext;
import org.apache.geode.internal.process.ProcessType;
import org.apache.geode.internal.process.UnableToControlProcessException;
import org.apache.geode.internal.serialization.filter.SystemPropertyGlobalSerialFilterConfigurationFactory;
+import org.apache.geode.internal.serialization.filter.UnableToSetSerialFilterException;
import org.apache.geode.lang.AttachAPINotFoundException;
import org.apache.geode.logging.internal.executors.LoggingThread;
import org.apache.geode.logging.internal.log4j.api.LogService;
@@ -789,10 +790,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
if (isStartable()) {
INSTANCE.compareAndSet(null, this);
- boolean serializationFilterConfigured =
- new SystemPropertyGlobalSerialFilterConfigurationFactory()
- .create(new DistributedSerializableObjectConfig(getDistributedSystemProperties()))
- .configure();
+ boolean serializationFilterConfigured = configureGlobalSerialFilterIfEnabled();
try {
process = getControllableProcess();
@@ -891,6 +889,16 @@ public class ServerLauncher extends AbstractLauncher<String> {
getServiceName(), getWorkingDirectory(), getId()));
}
+ private boolean configureGlobalSerialFilterIfEnabled() {
+ try {
+ return new SystemPropertyGlobalSerialFilterConfigurationFactory()
+ .create(new DistributedSerializableObjectConfig(getDistributedSystemProperties()))
+ .configure();
+ } catch (UnableToSetSerialFilterException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
Cache createCache(Properties gemfireProperties) {
Iterable<ServerLauncherCacheProvider> loader = getServerLauncherCacheProviders();
for (ServerLauncherCacheProvider provider : loader) {
diff --git a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
index a679db74..27048c3 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
@@ -70,6 +70,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.TestOnly;
import org.apache.geode.CancelException;
import org.apache.geode.CanonicalInstantiator;
@@ -120,12 +121,13 @@ import org.apache.geode.internal.serialization.SerializationContext;
import org.apache.geode.internal.serialization.SerializationVersions;
import org.apache.geode.internal.serialization.StaticSerialization;
import org.apache.geode.internal.serialization.VersionedDataStream;
-import org.apache.geode.internal.serialization.filter.NullObjectInputFilter;
-import org.apache.geode.internal.serialization.filter.ObjectInputFilter;
-import org.apache.geode.internal.serialization.filter.ObjectInputFilterFactory;
-import org.apache.geode.internal.serialization.filter.ReflectiveFacadeObjectInputFilterFactory;
+import org.apache.geode.internal.serialization.filter.NullStreamSerialFilter;
+import org.apache.geode.internal.serialization.filter.ReflectiveFacadeStreamSerialFilterFactory;
import org.apache.geode.internal.serialization.filter.SanctionedSerializablesService;
import org.apache.geode.internal.serialization.filter.SerializableObjectConfig;
+import org.apache.geode.internal.serialization.filter.StreamSerialFilter;
+import org.apache.geode.internal.serialization.filter.StreamSerialFilterFactory;
+import org.apache.geode.internal.serialization.filter.UnableToSetSerialFilterException;
import org.apache.geode.internal.util.concurrent.CopyOnWriteHashMap;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.pdx.NonPortableClassException;
@@ -289,12 +291,12 @@ public abstract class InternalDataSerializer extends DataSerializer {
"org.apache.geode.cache.query.internal.cq.ServerCQImpl";
@Immutable
- private static final ObjectInputFilter defaultSerializationFilter = new NullObjectInputFilter();
+ private static final StreamSerialFilter defaultSerializationFilter = new NullStreamSerialFilter();
/**
* A deserialization filter for ObjectInputStreams
*/
@MakeNotStatic
- private static ObjectInputFilter serializationFilter = defaultSerializationFilter;
+ private static StreamSerialFilter serializationFilter = defaultSerializationFilter;
/**
* support for old GemFire clients and WAN sites - needed to enable moving from GemFire to Geode
*/
@@ -432,14 +434,14 @@ public abstract class InternalDataSerializer extends DataSerializer {
Collection<SanctionedSerializablesService> services) {
logger.info("initializing InternalDataSerializer with {} services", services.size());
- ObjectInputFilterFactory objectInputFilterFactory =
- new ReflectiveFacadeObjectInputFilterFactory();
+ StreamSerialFilterFactory objectInputFilterFactory =
+ new ReflectiveFacadeStreamSerialFilterFactory();
serializationFilter =
objectInputFilterFactory.create(config, loadSanctionedClassNames(services));
}
- @VisibleForTesting
+ @TestOnly
static void clearSerializationFilter() {
serializationFilter = defaultSerializationFilter;
}
@@ -2701,7 +2703,14 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
ObjectInput ois = new DSObjectInputStream(stream);
- serializationFilter.setFilterOn((ObjectInputStream) ois);
+
+ try {
+ serializationFilter.setFilterOn((ObjectInputStream) ois);
+ } catch (UnableToSetSerialFilterException e) {
+ // maintain existing behavior for validate-serializable-objects
+ throw new UnsupportedOperationException(e);
+ }
+
if (stream instanceof VersionedDataStream) {
KnownVersion v = ((VersionedDataStream) stream).getVersion();
if (KnownVersion.CURRENT != v && v != null) {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java b/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java
index 83f5925..7cc252d 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java
@@ -69,6 +69,7 @@ import org.apache.geode.internal.security.SecurableCommunicationChannel;
import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.internal.security.shiro.JMXShiroAuthenticator;
import org.apache.geode.internal.serialization.filter.FilterConfiguration;
+import org.apache.geode.internal.serialization.filter.UnableToSetSerialFilterException;
import org.apache.geode.internal.tcp.TCPConduit;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.management.ManagementException;
@@ -139,7 +140,11 @@ public class ManagementAgent {
}
public synchronized void startAgent() {
- filterConfiguration.configure();
+ try {
+ filterConfiguration.configure();
+ } catch (UnableToSetSerialFilterException e) {
+ throw new RuntimeException(e);
+ }
loadWebApplications();
if (!running && config.getJmxManagerPort() != 0) {
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/distributed/LocatorLauncherTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java
similarity index 97%
rename from geode-core/src/distributedTest/java/org/apache/geode/distributed/LocatorLauncherTest.java
rename to geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java
index d7ba3c5..5bcb6d4 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/distributed/LocatorLauncherTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java
@@ -30,7 +30,7 @@ import org.apache.geode.distributed.internal.InternalLocator;
public class LocatorLauncherTest {
@Test
- public void canBeMocked() throws Exception {
+ public void canBeMocked() {
LocatorLauncher mockLocatorLauncher = mock(LocatorLauncher.class);
InternalLocator mockInternalLocator = mock(InternalLocator.class);
diff --git a/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationWhenFilterIsAlreadySetIntegrationTest.java b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationWhenFilterIsAlreadySetIntegrationTest.java
new file mode 100644
index 0000000..89f3b91
--- /dev/null
+++ b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationWhenFilterIsAlreadySetIntegrationTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.mockito.Mockito.mock;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class GlobalSerialFilterConfigurationWhenFilterIsAlreadySetIntegrationTest {
+
+ @Before
+ public void filterIsAlreadySet() throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilterApiFactory factory = new ReflectiveObjectInputFilterApiFactory();
+ ObjectInputFilterApi api = factory.createObjectInputFilterApi();
+ Object filter = api.createFilter("*");
+ api.setSerialFilter(filter);
+ }
+
+ @Test
+ public void throwsObjectInputFilterException_whenFilterIsAlreadySet() {
+ FilterConfiguration configuration =
+ new GlobalSerialFilterConfiguration(mock(SerializableObjectConfig.class));
+
+ Throwable thrown = catchThrowable(() -> {
+ configuration.configure();
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(UnableToSetSerialFilterException.class)
+ .hasMessage(
+ "Unable to configure a global serialization filter because filter has already been set non-null.")
+ .hasCauseInstanceOf(InvocationTargetException.class)
+ .hasRootCauseInstanceOf(IllegalStateException.class)
+ .hasRootCauseMessage("Serial filter can only be set once");
+ }
+}
diff --git a/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationWhenObjectInputFilterNotFoundIntegrationTest.java b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationWhenObjectInputFilterNotFoundIntegrationTest.java
new file mode 100644
index 0000000..92d9937
--- /dev/null
+++ b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationWhenObjectInputFilterNotFoundIntegrationTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import org.apache.logging.log4j.Logger;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+
+public class GlobalSerialFilterConfigurationWhenObjectInputFilterNotFoundIntegrationTest {
+
+ private final boolean supportsObjectInputFilter = false;
+
+ private ReflectiveFacadeGlobalSerialFilterFactory globalSerialFilterFactory_throws;
+ private SerializableObjectConfig config;
+ private Logger logger;
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Before
+ public void whenObjectInputFilter_classNotFound() {
+ globalSerialFilterFactory_throws =
+ new ReflectiveFacadeGlobalSerialFilterFactory(() -> {
+ throw new UnsupportedOperationException(
+ new ClassNotFoundException("sun.misc.ObjectInputFilter"));
+ });
+ }
+
+ @Before
+ public void setUpMocks() {
+ config = mock(SerializableObjectConfig.class);
+ logger = mock(Logger.class);
+ }
+
+ @Test
+ public void doesNotThrow_whenEnableGlobalSerialFilterIsFalse_andObjectInputFilterClassNotFound() {
+ System.clearProperty("geode.enableGlobalSerialFilter");
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory();
+ FilterConfiguration configuration = factory.create(config);
+
+ assertThatCode(configuration::configure)
+ .doesNotThrowAnyException();
+ }
+
+ @Test
+ public void logsNothing_whenEnableGlobalSerialFilterIsFalse_andObjectInputFilterClassNotFound()
+ throws UnableToSetSerialFilterException {
+ System.clearProperty("geode.enableGlobalSerialFilter");
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory(() -> supportsObjectInputFilter);
+ FilterConfiguration configuration = factory.create(config);
+
+ configuration.configure();
+
+ verifyNoInteractions(logger);
+ }
+
+ @Test
+ public void doesNotConfigureOrThrow_whenEnableGlobalSerialFilterIsTrue_andObjectInputFilterClassNotFound()
+ throws UnableToSetSerialFilterException {
+ System.setProperty("geode.enableGlobalSerialFilter", "true");
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory(() -> supportsObjectInputFilter);
+ FilterConfiguration configuration = factory.create(config);
+
+ boolean result = configuration.configure();
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void logsWarning_whenEnableGlobalSerialFilterIsTrue_andObjectInputFilterClassNotFound() {
+ System.setProperty("geode.enableGlobalSerialFilter", "true");
+ FilterConfiguration configuration = new GlobalSerialFilterConfiguration(
+ config, logger, globalSerialFilterFactory_throws);
+
+ Throwable thrown = catchThrowable(() -> {
+ configuration.configure();
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessage("java.lang.ClassNotFoundException: sun.misc.ObjectInputFilter")
+ .hasRootCauseInstanceOf(ClassNotFoundException.class)
+ .hasRootCauseMessage("sun.misc.ObjectInputFilter");
+ }
+}
diff --git a/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest.java b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest.java
index 6155c8b..d5714f6 100644
--- a/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest.java
+++ b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest.java
@@ -44,7 +44,6 @@ public class ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest {
if (isJavaVersionAtLeast(JAVA_9)) {
apiPackage = JAVA_IO;
}
-
}
@Test
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterAlreadyConfiguredException.java
similarity index 58%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterAlreadyConfiguredException.java
index e25c073..e42990e 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterAlreadyConfiguredException.java
@@ -14,15 +14,23 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.ObjectInputStream;
-
/**
- * Implementation of {@code ObjectInputFilter} that does nothing.
+ * Checked exception thrown when configuring a filter fails because a non-null filter already
+ * exists. All uses of this exception are caught and rethrown before reaching the user.
*/
-public class NullObjectInputFilter implements ObjectInputFilter {
+public class FilterAlreadyConfiguredException extends UnableToSetSerialFilterException {
+
+ public FilterAlreadyConfiguredException(String message) {
+ super(message);
+ }
- @Override
- public void setFilterOn(ObjectInputStream objectInputStream) {
- // Do nothing, this is the case where we don't filter.
+ public FilterAlreadyConfiguredException(String message, Throwable cause) {
+ super(message, cause);
}
+
+ public FilterAlreadyConfiguredException(Throwable cause) {
+ super(cause);
+ }
+
+ private static final long serialVersionUID = -6102549374563510704L;
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterConfiguration.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterConfiguration.java
index 9a51a28..cf12790 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterConfiguration.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterConfiguration.java
@@ -23,5 +23,5 @@ public interface FilterConfiguration {
/**
* Returns true if serialization filter was successfully configured.
*/
- boolean configure();
+ boolean configure() throws UnableToSetSerialFilterException;
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilter.java
index 87c19bd..7858878 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilter.java
@@ -22,6 +22,9 @@ interface GlobalSerialFilter {
/**
* Sets this serialization filter as the process-wide filter.
+ *
+ * @throws FilterAlreadyConfiguredException if a non-null serialization filter already exists
+ * @throws UnableToSetSerialFilterException if there's any failure setting a serialization filter
*/
- void setFilter();
+ void setFilter() throws UnableToSetSerialFilterException;
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfiguration.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfiguration.java
index c7d9585..e60c49d 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfiguration.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfiguration.java
@@ -14,13 +14,10 @@
*/
package org.apache.geode.internal.serialization.filter;
-import static java.util.Objects.nonNull;
-import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCause;
import static org.apache.geode.internal.serialization.filter.SanctionedSerializables.loadSanctionedClassNames;
import static org.apache.geode.internal.serialization.filter.SanctionedSerializables.loadSanctionedSerializablesServices;
import java.util.Set;
-import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.logging.log4j.Logger;
@@ -38,7 +35,7 @@ class GlobalSerialFilterConfiguration implements FilterConfiguration {
private final SerializableObjectConfig serializableObjectConfig;
private final FilterPatternFactory filterPatternFactory;
private final Supplier<Set<String>> sanctionedClassesSupplier;
- private final Consumer<String> logger;
+ private final Logger logger;
private final GlobalSerialFilterFactory globalSerialFilterFactory;
/**
@@ -46,16 +43,24 @@ class GlobalSerialFilterConfiguration implements FilterConfiguration {
*/
GlobalSerialFilterConfiguration(SerializableObjectConfig serializableObjectConfig) {
this(serializableObjectConfig,
- new DefaultFilterPatternFactory(),
- () -> loadSanctionedClassNames(loadSanctionedSerializablesServices()),
- LOGGER::info,
(pattern, sanctionedClasses) -> new ReflectiveFacadeGlobalSerialFilterFactory()
.create(pattern, sanctionedClasses));
}
@TestOnly
- GlobalSerialFilterConfiguration(SerializableObjectConfig serializableObjectConfig,
- Consumer<String> logger, GlobalSerialFilterFactory globalSerialFilterFactory) {
+ GlobalSerialFilterConfiguration(
+ SerializableObjectConfig serializableObjectConfig,
+ GlobalSerialFilterFactory globalSerialFilterFactory) {
+ this(serializableObjectConfig,
+ LOGGER,
+ globalSerialFilterFactory);
+ }
+
+ @TestOnly
+ GlobalSerialFilterConfiguration(
+ SerializableObjectConfig serializableObjectConfig,
+ Logger logger,
+ GlobalSerialFilterFactory globalSerialFilterFactory) {
this(serializableObjectConfig,
new DefaultFilterPatternFactory(),
() -> loadSanctionedClassNames(loadSanctionedSerializablesServices()),
@@ -67,7 +72,7 @@ class GlobalSerialFilterConfiguration implements FilterConfiguration {
SerializableObjectConfig serializableObjectConfig,
FilterPatternFactory filterPatternFactory,
Supplier<Set<String>> sanctionedClassesSupplier,
- Consumer<String> logger,
+ Logger logger,
GlobalSerialFilterFactory globalSerialFilterFactory) {
this.serializableObjectConfig = serializableObjectConfig;
this.filterPatternFactory = filterPatternFactory;
@@ -77,48 +82,23 @@ class GlobalSerialFilterConfiguration implements FilterConfiguration {
}
@Override
- public boolean configure() {
- try {
- // enable validate-serializable-objects
- serializableObjectConfig.setValidateSerializableObjects(true);
-
- // create a GlobalSerialFilter
- String pattern = filterPatternFactory
- .create(serializableObjectConfig.getSerializableObjectFilterIfEnabled());
- Set<String> sanctionedClasses = sanctionedClassesSupplier.get();
- GlobalSerialFilter globalSerialFilter =
- globalSerialFilterFactory.create(pattern, sanctionedClasses);
-
- // invoke setFilter on GlobalSerialFilter to set the process-wide filter
- globalSerialFilter.setFilter();
-
- // log statement that filter is now configured
- logger.accept("Global serial filter is now configured.");
- return true;
-
- } catch (UnsupportedOperationException e) {
- if (hasRootCauseWithMessage(e, IllegalStateException.class,
- "Serial filter can only be set once")) {
-
- // log statement that filter was already configured
- logger.accept("Global serial filter is already configured.");
- }
- return false;
- }
- }
-
- private static boolean hasRootCauseWithMessage(Throwable throwable,
- Class<? extends Throwable> causeClass, String message) {
- Throwable rootCause = getRootCause(throwable);
- return isInstanceOf(rootCause, causeClass) && hasMessage(rootCause, message);
- }
-
- private static boolean isInstanceOf(Throwable throwable, Class<? extends Throwable> causeClass) {
- return nonNull(throwable) && throwable.getClass().equals(causeClass);
- }
-
- private static boolean hasMessage(Throwable throwable, String message) {
- return nonNull(throwable) && throwable.getMessage().equalsIgnoreCase(message);
+ public boolean configure() throws UnableToSetSerialFilterException {
+ // enable validate-serializable-objects
+ serializableObjectConfig.setValidateSerializableObjects(true);
+
+ // create a GlobalSerialFilter
+ String pattern = filterPatternFactory
+ .create(serializableObjectConfig.getSerializableObjectFilterIfEnabled());
+ Set<String> sanctionedClasses = sanctionedClassesSupplier.get();
+ GlobalSerialFilter globalSerialFilter =
+ globalSerialFilterFactory.create(pattern, sanctionedClasses);
+
+ // invoke setFilter on GlobalSerialFilter to set the process-wide filter
+ globalSerialFilter.setFilter();
+
+ // log statement that filter is now configured
+ logger.info("Global serialization filter is now configured.");
+ return true;
}
/**
@@ -134,7 +114,7 @@ class GlobalSerialFilterConfiguration implements FilterConfiguration {
/**
* Default implementation of {@code FilterPatternFactory}.
*/
- static class DefaultFilterPatternFactory implements FilterPatternFactory {
+ public static class DefaultFilterPatternFactory implements FilterPatternFactory {
@Override
public String create(String optionalSerializableObjectFilter) {
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfiguration.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfiguration.java
index 21b0908..86c7191 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfiguration.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfiguration.java
@@ -16,8 +16,6 @@ package org.apache.geode.internal.serialization.filter;
import static org.apache.commons.lang3.StringUtils.isBlank;
-import java.util.function.Consumer;
-
import org.apache.logging.log4j.Logger;
import org.apache.geode.annotations.VisibleForTesting;
@@ -42,17 +40,20 @@ class JmxSerialFilterConfiguration implements FilterConfiguration {
private final String key;
private final String value;
- private final Consumer<String> logger;
+ private final Logger logger;
/**
* Constructs instance for the specified system property and filter pattern.
*/
JmxSerialFilterConfiguration(String property, String pattern) {
- this(property, pattern, LOGGER::info);
+ this(property, pattern, LOGGER);
}
@VisibleForTesting
- JmxSerialFilterConfiguration(String property, String pattern, Consumer<String> logger) {
+ JmxSerialFilterConfiguration(
+ String property,
+ String pattern,
+ Logger logger) {
key = property;
value = pattern;
this.logger = logger;
@@ -62,11 +63,11 @@ class JmxSerialFilterConfiguration implements FilterConfiguration {
public boolean configure() {
if (isBlank(System.getProperty(key))) {
System.setProperty(key, value);
- logger.accept("System property '" + key + "' is now configured with '" + value + "'.");
+ logger.info("System property '" + key + "' is now configured with '" + value + "'.");
return true;
}
- logger.accept("System property '" + key + "' is already configured.");
+ logger.info("System property '" + key + "' is already configured.");
return false;
}
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullStreamSerialFilter.java
similarity index 88%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullStreamSerialFilter.java
index e25c073..226159b 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullStreamSerialFilter.java
@@ -17,9 +17,9 @@ package org.apache.geode.internal.serialization.filter;
import java.io.ObjectInputStream;
/**
- * Implementation of {@code ObjectInputFilter} that does nothing.
+ * Implementation of {@code StreamSerialFilter} that does nothing.
*/
-public class NullObjectInputFilter implements ObjectInputFilter {
+public class NullStreamSerialFilter implements StreamSerialFilter {
@Override
public void setFilterOn(ObjectInputStream objectInputStream) {
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterInvocationHandler.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterInvocationHandler.java
new file mode 100644
index 0000000..7c084b6
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterInvocationHandler.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.serialization.filter;
+
+import static java.util.Collections.unmodifiableCollection;
+import static java.util.Objects.requireNonNull;
+
+import java.io.InvalidClassException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Collection;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.logging.internal.log4j.api.LogService;
+
+class ObjectInputFilterInvocationHandler implements InvocationHandler {
+
+ private static final Logger logger = LogService.getLogger();
+
+ private final Method ObjectInputFilter_checkInput;
+ private final Method ObjectInputFilter_FilterInfo_serialClass;
+ private final Object ObjectInputFilter_Status_ALLOWED;
+ private final Object ObjectInputFilter_Status_REJECTED;
+
+ private final Object objectInputFilter;
+ private final Collection<String> sanctionedClasses;
+
+ ObjectInputFilterInvocationHandler(
+ Method ObjectInputFilter_checkInput,
+ Method ObjectInputFilter_FilterInfo_serialClass,
+ Object ObjectInputFilter_Status_ALLOWED,
+ Object ObjectInputFilter_Status_REJECTED,
+ Object objectInputFilter,
+ Collection<String> sanctionedClasses) {
+ this.ObjectInputFilter_checkInput = ObjectInputFilter_checkInput;
+ this.ObjectInputFilter_FilterInfo_serialClass = ObjectInputFilter_FilterInfo_serialClass;
+ this.ObjectInputFilter_Status_ALLOWED = ObjectInputFilter_Status_ALLOWED;
+ this.ObjectInputFilter_Status_REJECTED = ObjectInputFilter_Status_REJECTED;
+ this.objectInputFilter = objectInputFilter;
+ this.sanctionedClasses = unmodifiableCollection(sanctionedClasses);
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws IllegalAccessException, IllegalArgumentException,
+ java.lang.reflect.InvocationTargetException {
+ if (!"checkInput".equals(method.getName())) {
+ // delegate to the actual objectInputFilter instance for any method other than checkInput
+ return method.invoke(objectInputFilter, args);
+ }
+
+ requireNonNull(args, "Single argument FilterInfo is null");
+
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Single argument FilterInfo is required");
+ }
+
+ // fetch the class of the serialized instance
+ Object objectInputFilter_filterInfo = args[0];
+ Class<?> serialClass =
+ (Class<?>) ObjectInputFilter_FilterInfo_serialClass.invoke(objectInputFilter_filterInfo);
+ if (serialClass == null) { // no class to check, so nothing to accept-list
+ return ObjectInputFilter_checkInput.invoke(objectInputFilter, objectInputFilter_filterInfo);
+ }
+
+ // check sanctionedClasses to determine if the name of the class is ALLOWED
+ String serialClassName = serialClass.getName();
+ if (serialClass.isArray()) {
+ serialClassName = serialClass.getComponentType().getName();
+ }
+ if (sanctionedClasses.contains(serialClassName)) {
+ return ObjectInputFilter_Status_ALLOWED;
+ }
+
+ // check the filter to determine if the class is ALLOWED
+ Object objectInputFilter_Status =
+ ObjectInputFilter_checkInput.invoke(objectInputFilter, objectInputFilter_filterInfo);
+ if (objectInputFilter_Status == ObjectInputFilter_Status_REJECTED) {
+ logger.fatal("Serialization filter is rejecting class {}", serialClassName,
+ new InvalidClassException(serialClassName));
+ }
+ return objectInputFilter_Status;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(getClass().getSimpleName())
+ .append("@")
+ .append(Integer.toHexString(hashCode()))
+ .append('{')
+ .append("objectInputFilter=").append(objectInputFilter)
+ .append(", sanctionedClassesCount=").append(sanctionedClasses.size())
+ .append('}')
+ .toString();
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilter.java
index 4a1152d..164bffc 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilter.java
@@ -15,7 +15,8 @@
package org.apache.geode.internal.serialization.filter;
import static java.util.Collections.unmodifiableCollection;
-import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.throwUnsupportedOperationException;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCause;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
@@ -35,7 +36,7 @@ class ReflectiveFacadeGlobalSerialFilter implements GlobalSerialFilter {
*/
ReflectiveFacadeGlobalSerialFilter(ObjectInputFilterApi api, String pattern,
Collection<String> sanctionedClasses) {
- this.api = api;
+ this.api = requireNonNull(api, "ObjectInputFilterApi is required");
this.pattern = pattern;
this.sanctionedClasses = unmodifiableCollection(sanctionedClasses);
}
@@ -44,7 +45,7 @@ class ReflectiveFacadeGlobalSerialFilter implements GlobalSerialFilter {
* Invokes interface-defined operation to set this as the process-wide filter.
*/
@Override
- public void setFilter() {
+ public void setFilter() throws UnableToSetSerialFilterException {
try {
// create the ObjectInputFilter to set as the global serial filter
Object objectInputFilter = api.createObjectInputFilterProxy(pattern, sanctionedClasses);
@@ -53,9 +54,7 @@ class ReflectiveFacadeGlobalSerialFilter implements GlobalSerialFilter {
api.setSerialFilter(objectInputFilter);
} catch (IllegalAccessException | InvocationTargetException e) {
- throwUnsupportedOperationException(
- "Geode was unable to configure a global serialization filter",
- e);
+ handleExceptionThrownByApi(e);
}
}
@@ -68,4 +67,36 @@ class ReflectiveFacadeGlobalSerialFilter implements GlobalSerialFilter {
.append('}')
.toString();
}
+
+ private void handleExceptionThrownByApi(ReflectiveOperationException e)
+ throws UnableToSetSerialFilterException {
+ String className = getClassName(e);
+ switch (className) {
+ case "java.lang.IllegalAccessException":
+ throw new UnableToSetSerialFilterException(
+ "Unable to configure a global serialization filter using reflection.",
+ e);
+ case "java.lang.reflect.InvocationTargetException":
+ if (getRootCause(e) instanceof IllegalStateException) {
+ // ObjectInputFilter throws IllegalStateException
+ // if the filter has already been set non-null
+ throw new FilterAlreadyConfiguredException(
+ "Unable to configure a global serialization filter because filter has already been set non-null.",
+ e);
+ }
+ String causeClassName = e.getCause() == null ? getClassName(e) : getClassName(e.getCause());
+ throw new UnableToSetSerialFilterException(
+ "Unable to configure a global serialization filter because invocation target threw "
+ + causeClassName + ".",
+ e);
+ default:
+ throw new UnableToSetSerialFilterException(
+ "Unable to configure a global serialization filter.",
+ e);
+ }
+ }
+
+ private static String getClassName(Throwable throwable) {
+ return throwable.getClass().getName();
+ }
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
index 022c766..3826e00 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
@@ -14,11 +14,8 @@
*/
package org.apache.geode.internal.serialization.filter;
-import static java.util.Objects.requireNonNull;
-
import java.util.Collection;
-
-import org.apache.geode.annotations.VisibleForTesting;
+import java.util.function.Supplier;
/**
* Creates an instance of {@code GlobalSerialFilter} that delegates to {@code ObjectInputFilterApi}
@@ -26,19 +23,24 @@ import org.apache.geode.annotations.VisibleForTesting;
*/
class ReflectiveFacadeGlobalSerialFilterFactory implements GlobalSerialFilterFactory {
- private final ObjectInputFilterApi api;
+ private final Supplier<ObjectInputFilterApi> objectInputFilterApiSupplier;
ReflectiveFacadeGlobalSerialFilterFactory() {
- this(new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi());
+ this(() -> new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi());
+ }
+
+ ReflectiveFacadeGlobalSerialFilterFactory(ObjectInputFilterApi objectInputFilterApi) {
+ this(() -> objectInputFilterApi);
}
- @VisibleForTesting
- ReflectiveFacadeGlobalSerialFilterFactory(ObjectInputFilterApi api) {
- this.api = requireNonNull(api, "ObjectInputFilterApi is required");
+ ReflectiveFacadeGlobalSerialFilterFactory(
+ Supplier<ObjectInputFilterApi> objectInputFilterApiSupplier) {
+ this.objectInputFilterApiSupplier = objectInputFilterApiSupplier;
}
@Override
public GlobalSerialFilter create(String pattern, Collection<String> sanctionedClasses) {
+ ObjectInputFilterApi api = objectInputFilterApiSupplier.get();
return new ReflectiveFacadeGlobalSerialFilter(api, pattern, sanctionedClasses);
}
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactory.java
deleted file mode 100644
index a38416c..0000000
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.serialization.filter;
-
-import static java.util.Objects.requireNonNull;
-import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.supportsObjectInputFilter;
-import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.throwUnsupportedOperationException;
-
-import java.util.Set;
-
-/**
- * Creates an instance of {@code ObjectInputFilter} that delegates to {@code ObjectInputFilterApi}
- * to maintain independence from the JRE version.
- */
-public class ReflectiveFacadeObjectInputFilterFactory implements ObjectInputFilterFactory {
-
- private static final String UNSUPPORTED_MESSAGE =
- "A serialization filter has been specified but this version of Java does not support serialization filters - ObjectInputFilter is not available";
-
- private final ObjectInputFilterApi api;
-
- public ReflectiveFacadeObjectInputFilterFactory() {
- this(new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi());
- }
-
- private ReflectiveFacadeObjectInputFilterFactory(ObjectInputFilterApi api) {
- this.api = requireNonNull(api, "ObjectInputFilterApi is required");
- }
-
- @Override
- public ObjectInputFilter create(SerializableObjectConfig config, Set<String> sanctionedClasses) {
- if (config.getValidateSerializableObjects()) {
- requireObjectInputFilter();
-
- String pattern = new SanctionedSerializablesFilterPattern()
- .append(config.getSerializableObjectFilter())
- .pattern();
-
- return new ReflectiveFacadeObjectInputFilter(api, pattern, sanctionedClasses);
- }
- return new NullObjectInputFilter();
- }
-
- public static void requireObjectInputFilter() {
- if (!supportsObjectInputFilter()) {
- throwUnsupportedOperationException(UNSUPPORTED_MESSAGE);
- }
- }
-}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeStreamSerialFilter.java
similarity index 55%
rename from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilter.java
rename to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeStreamSerialFilter.java
index 042fb4d..7da2d6a 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeStreamSerialFilter.java
@@ -15,7 +15,8 @@
package org.apache.geode.internal.serialization.filter;
import static java.util.Collections.unmodifiableCollection;
-import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.throwUnsupportedOperationException;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCause;
import java.io.ObjectInputStream;
import java.lang.reflect.InvocationTargetException;
@@ -27,7 +28,7 @@ import org.jetbrains.annotations.TestOnly;
* Implementation of {@code ObjectInputFilter} that delegates to {@code ObjectInputFilterApi} to
* maintain independence from the JRE version.
*/
-class ReflectiveFacadeObjectInputFilter implements ObjectInputFilter {
+class ReflectiveFacadeStreamSerialFilter implements StreamSerialFilter {
private final ObjectInputFilterApi api;
private final String pattern;
@@ -36,11 +37,11 @@ class ReflectiveFacadeObjectInputFilter implements ObjectInputFilter {
/**
* Constructs instance with the specified collaborators.
*/
- ReflectiveFacadeObjectInputFilter(ObjectInputFilterApi api, String pattern,
+ ReflectiveFacadeStreamSerialFilter(ObjectInputFilterApi api, String pattern,
Collection<String> sanctionedClasses) {
+ this.api = requireNonNull(api, "ObjectInputFilterApi is required");
this.pattern = pattern;
this.sanctionedClasses = unmodifiableCollection(sanctionedClasses);
- this.api = api;
}
/**
@@ -48,7 +49,8 @@ class ReflectiveFacadeObjectInputFilter implements ObjectInputFilter {
* {@code ObjectInputStream}.
*/
@Override
- public void setFilterOn(ObjectInputStream objectInputStream) {
+ public void setFilterOn(ObjectInputStream objectInputStream)
+ throws UnableToSetSerialFilterException {
try {
// create the ObjectInputFilter to set as the global serial filter
Object objectInputFilter = api.createObjectInputFilterProxy(pattern, sanctionedClasses);
@@ -57,10 +59,7 @@ class ReflectiveFacadeObjectInputFilter implements ObjectInputFilter {
api.setObjectInputFilter(objectInputStream, objectInputFilter);
} catch (IllegalAccessException | InvocationTargetException e) {
- throwUnsupportedOperationException(
- "Geode was unable to configure a serialization filter on input stream '"
- + objectInputStream.hashCode() + "'",
- e);
+ handleExceptionThrownByApi(e);
}
}
@@ -78,4 +77,36 @@ class ReflectiveFacadeObjectInputFilter implements ObjectInputFilter {
ObjectInputFilterApi getObjectInputFilterApi() {
return api;
}
+
+ private void handleExceptionThrownByApi(ReflectiveOperationException e)
+ throws UnableToSetSerialFilterException {
+ String className = getClassName(e);
+ switch (className) {
+ case "java.lang.IllegalAccessException":
+ throw new UnableToSetSerialFilterException(
+ "Unable to configure an input stream serialization filter using reflection.",
+ e);
+ case "java.lang.reflect.InvocationTargetException":
+ if (getRootCause(e) instanceof IllegalStateException) {
+ // ObjectInputFilter throws IllegalStateException
+ // if the filter has already been set non-null
+ throw new FilterAlreadyConfiguredException(
+ "Unable to configure an input stream serialization filter because a non-null filter has already been set.",
+ e);
+ }
+ String causeClassName = e.getCause() == null ? getClassName(e) : getClassName(e.getCause());
+ throw new UnableToSetSerialFilterException(
+ "Unable to configure an input stream serialization filter because invocation target threw "
+ + causeClassName + ".",
+ e);
+ default:
+ throw new UnableToSetSerialFilterException(
+ "Unable to configure an input stream serialization filter.",
+ e);
+ }
+ }
+
+ private static String getClassName(Throwable throwable) {
+ return throwable.getClass().getName();
+ }
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeStreamSerialFilterFactory.java
similarity index 52%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeStreamSerialFilterFactory.java
index 022c766..3c47998 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeStreamSerialFilterFactory.java
@@ -14,31 +14,26 @@
*/
package org.apache.geode.internal.serialization.filter;
-import static java.util.Objects.requireNonNull;
-
-import java.util.Collection;
-
-import org.apache.geode.annotations.VisibleForTesting;
+import java.util.Set;
/**
- * Creates an instance of {@code GlobalSerialFilter} that delegates to {@code ObjectInputFilterApi}
+ * Creates an instance of {@code ObjectInputFilter} that delegates to {@code ObjectInputFilterApi}
* to maintain independence from the JRE version.
*/
-class ReflectiveFacadeGlobalSerialFilterFactory implements GlobalSerialFilterFactory {
-
- private final ObjectInputFilterApi api;
-
- ReflectiveFacadeGlobalSerialFilterFactory() {
- this(new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi());
- }
-
- @VisibleForTesting
- ReflectiveFacadeGlobalSerialFilterFactory(ObjectInputFilterApi api) {
- this.api = requireNonNull(api, "ObjectInputFilterApi is required");
- }
+public class ReflectiveFacadeStreamSerialFilterFactory implements StreamSerialFilterFactory {
@Override
- public GlobalSerialFilter create(String pattern, Collection<String> sanctionedClasses) {
- return new ReflectiveFacadeGlobalSerialFilter(api, pattern, sanctionedClasses);
+ public StreamSerialFilter create(SerializableObjectConfig config, Set<String> sanctionedClasses) {
+ ObjectInputFilterApi api =
+ new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi();
+
+ if (config.getValidateSerializableObjects()) {
+ String pattern = new SanctionedSerializablesFilterPattern()
+ .append(config.getSerializableObjectFilter())
+ .pattern();
+
+ return new ReflectiveFacadeStreamSerialFilter(api, pattern, sanctionedClasses);
+ }
+ return new NullStreamSerialFilter();
}
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApi.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApi.java
index 10c3aad..7b2e40a 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApi.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApi.java
@@ -14,7 +14,6 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
@@ -22,10 +21,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
-import org.apache.logging.log4j.Logger;
-
import org.apache.geode.annotations.VisibleForTesting;
-import org.apache.geode.logging.internal.log4j.api.LogService;
/**
* Implementation of {@code ObjectInputFilterApi} that uses reflection and a dynamic proxy to wrap
@@ -33,19 +29,17 @@ import org.apache.geode.logging.internal.log4j.api.LogService;
*/
public class ReflectiveObjectInputFilterApi implements ObjectInputFilterApi {
- private static final Logger logger = LogService.getLogger();
-
protected final ApiPackage apiPackage;
// api.package.ObjectInputFilter
protected final Class<?> ObjectInputFilter;
- private final Method ObjectInputFilter_checkInput;
- private final Object ObjectInputFilter_Status_ALLOWED;
- private final Object ObjectInputFilter_Status_REJECTED;
+ protected final Method ObjectInputFilter_checkInput;
+ protected final Object ObjectInputFilter_Status_ALLOWED;
+ protected final Object ObjectInputFilter_Status_REJECTED;
// api.package.ObjectInputFilter$Config
- private final Class<?> ObjectInputFilter_Config;
- private final Method ObjectInputFilter_Config_createFilter;
+ protected final Class<?> ObjectInputFilter_Config;
+ protected final Method ObjectInputFilter_Config_createFilter;
private final Method ObjectInputFilter_Config_getObjectInputFilter;
private final Method ObjectInputFilter_Config_setObjectInputFilter;
private final Method ObjectInputFilter_Config_getSerialFilter;
@@ -53,7 +47,7 @@ public class ReflectiveObjectInputFilterApi implements ObjectInputFilterApi {
// api.package.ObjectInputFilter$FilterInfo
private final Class<?> ObjectInputFilter_FilterInfo;
- private final Method ObjectInputFilter_FilterInfo_serialClass;
+ protected final Method ObjectInputFilter_FilterInfo_serialClass;
/**
* Use reflection to look up the classes and methods for the API.
@@ -144,43 +138,18 @@ public class ReflectiveObjectInputFilterApi implements ObjectInputFilterApi {
* effectively override the call to widen the filter to include the User's addition to the set
* of sanctioned serializables.
*/
- InvocationHandler invocationHandler = (proxy, method, args) -> {
- if (!"checkInput".equals(method.getName())) {
- throw new UnsupportedOperationException(
- "ObjectInputFilter." + method.getName() + " is not implemented");
- }
-
- // fetch the class of the serialized instance
- Object objectInputFilter_filterInfo = args[0];
- Class<?> serialClass =
- (Class<?>) ObjectInputFilter_FilterInfo_serialClass.invoke(objectInputFilter_filterInfo);
- if (serialClass == null) { // no class to check, so nothing to accept-list
- return ObjectInputFilter_checkInput.invoke(objectInputFilter, objectInputFilter_filterInfo);
- }
-
- // check sanctionedClasses to determine if the name of the class is ALLOWED
- String serialClassName = serialClass.getName();
- if (serialClass.isArray()) {
- serialClassName = serialClass.getComponentType().getName();
- }
- if (sanctionedClasses.contains(serialClassName)) {
- return ObjectInputFilter_Status_ALLOWED;
- }
-
- // check the filter to determine if the class is ALLOWED
- Object objectInputFilter_Status =
- ObjectInputFilter_checkInput.invoke(objectInputFilter, objectInputFilter_filterInfo);
- if (objectInputFilter_Status == ObjectInputFilter_Status_REJECTED) {
- logger.fatal("Serialization filter is rejecting class {}", serialClassName,
- new InvalidClassException(serialClassName));
- }
- return objectInputFilter_Status;
- };
+ InvocationHandler invocationHandler = new ObjectInputFilterInvocationHandler(
+ ObjectInputFilter_checkInput,
+ ObjectInputFilter_FilterInfo_serialClass,
+ ObjectInputFilter_Status_ALLOWED,
+ ObjectInputFilter_Status_REJECTED,
+ objectInputFilter,
+ sanctionedClasses);
// wrap the filter within a proxy to inject the above invocation handler
return Proxy.newProxyInstance(
ObjectInputFilter.getClassLoader(),
- new Class[] {ObjectInputFilter},
+ new Class<?>[] {ObjectInputFilter},
invocationHandler);
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/StreamSerialFilter.java
similarity index 76%
rename from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilter.java
rename to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/StreamSerialFilter.java
index 091f8f6..1d182e4 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/StreamSerialFilter.java
@@ -20,10 +20,13 @@ import java.io.ObjectInputStream;
* Defines operation to set this serialization filter on an {@code ObjectInputStream}.
*/
@FunctionalInterface
-public interface ObjectInputFilter {
+public interface StreamSerialFilter {
/**
* Sets this serialization filter on the specified {@code ObjectInputStream}.
+ *
+ * @throws FilterAlreadyConfiguredException if a non-null serialization filter already exists
+ * @throws UnableToSetSerialFilterException if there's any failure setting a serialization filter
*/
- void setFilterOn(ObjectInputStream objectInputStream);
+ void setFilterOn(ObjectInputStream objectInputStream) throws UnableToSetSerialFilterException;
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/StreamSerialFilterFactory.java
similarity index 88%
rename from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterFactory.java
rename to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/StreamSerialFilterFactory.java
index c5fe4bf..c5a3113 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterFactory.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/StreamSerialFilterFactory.java
@@ -17,8 +17,8 @@ package org.apache.geode.internal.serialization.filter;
import java.util.Set;
@FunctionalInterface
-public interface ObjectInputFilterFactory {
+public interface StreamSerialFilterFactory {
- ObjectInputFilter create(SerializableObjectConfig serializableObjectConfig,
+ StreamSerialFilter create(SerializableObjectConfig serializableObjectConfig,
Set<String> sanctionedClasses);
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactory.java
index 4c592d3..b78cbfd 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactory.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactory.java
@@ -16,6 +16,8 @@ package org.apache.geode.internal.serialization.filter;
import static org.apache.commons.lang3.StringUtils.isBlank;
+import java.util.function.BooleanSupplier;
+
import org.apache.geode.internal.lang.SystemProperty;
/**
@@ -30,9 +32,15 @@ public class SystemPropertyGlobalSerialFilterConfigurationFactory
public SystemPropertyGlobalSerialFilterConfigurationFactory() {
// enable GlobalSerialFilter only under these conditions:
- // (1) jdk.serialFilter must be blank
- // (2) geode.enableGlobalSerialFilter must be set "true"
- this(isBlank(System.getProperty("jdk.serialFilter")) &&
+ // (1) JRE supports ObjectInputFilter in either sun.misc. or java.io. package
+ // (2) jdk.serialFilter must be blank
+ // (3) geode.enableGlobalSerialFilter must be set "true"
+ this(ObjectInputFilterUtils::supportsObjectInputFilter);
+ }
+
+ SystemPropertyGlobalSerialFilterConfigurationFactory(BooleanSupplier supportsObjectInputFilter) {
+ this(supportsObjectInputFilter.getAsBoolean() &&
+ isBlank(System.getProperty("jdk.serialFilter")) &&
SystemProperty
.getProductBooleanProperty("enableGlobalSerialFilter")
.orElse(false));
@@ -47,6 +55,14 @@ public class SystemPropertyGlobalSerialFilterConfigurationFactory
if (enabled) {
return new GlobalSerialFilterConfiguration(serializableObjectConfig);
}
- return () -> false;
+ return new NullFilterConfiguration();
+ }
+
+ private static class NullFilterConfiguration implements FilterConfiguration {
+
+ @Override
+ public boolean configure() {
+ return false;
+ }
}
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/UnableToSetSerialFilterException.java
similarity index 60%
rename from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
rename to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/UnableToSetSerialFilterException.java
index e25c073..a8683c8 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/UnableToSetSerialFilterException.java
@@ -14,15 +14,23 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.ObjectInputStream;
-
/**
- * Implementation of {@code ObjectInputFilter} that does nothing.
+ * Checked exception thrown when there's a failure using Java's ObjectInputFilter. All uses of this
+ * exception are caught and rethrown before reaching the user.
*/
-public class NullObjectInputFilter implements ObjectInputFilter {
+public class UnableToSetSerialFilterException extends Exception {
+
+ public UnableToSetSerialFilterException(String message) {
+ super(message);
+ }
- @Override
- public void setFilterOn(ObjectInputStream objectInputStream) {
- // Do nothing, this is the case where we don't filter.
+ public UnableToSetSerialFilterException(String message, Throwable cause) {
+ super(message, cause);
}
+
+ public UnableToSetSerialFilterException(Throwable cause) {
+ super(cause);
+ }
+
+ private static final long serialVersionUID = 3406028558181224120L;
}
diff --git a/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt b/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt
index 3133970..29fa124 100644
--- a/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt
+++ b/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt
@@ -2,3 +2,5 @@ org/apache/geode/internal/serialization/DSCODE,false,value:byte
org/apache/geode/internal/serialization/DSFIDNotFoundException,true,130596009484324655,dsfid:int,versionOrdinal:short
org/apache/geode/internal/serialization/UnsupportedSerializationVersionException,true,3572445857994216007
org/apache/geode/internal/serialization/filter/ApiPackage,false,prefix:java/lang/String
+org/apache/geode/internal/serialization/filter/FilterAlreadyConfiguredException,true,-6102549374563510704
+org/apache/geode/internal/serialization/filter/UnableToSetSerialFilterException,true,3406028558181224120
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationTest.java
index e31126b..2f02ed5 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationTest.java
@@ -14,60 +14,102 @@
*/
package org.apache.geode.internal.serialization.filter;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoInteractions;
-import java.util.function.Consumer;
+import java.lang.reflect.InvocationTargetException;
+import org.apache.logging.log4j.Logger;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class GlobalSerialFilterConfigurationTest {
- private SerializableObjectConfig config;
+ private SerializableObjectConfig serializableObjectConfig;
private GlobalSerialFilter globalSerialFilter;
- private Consumer<String> logger;
+ private Logger logger;
@Before
public void setUp() {
- config = mock(SerializableObjectConfig.class);
+ serializableObjectConfig = mock(SerializableObjectConfig.class);
globalSerialFilter = mock(GlobalSerialFilter.class);
- logger = uncheckedCast(mock(Consumer.class));
+ logger = uncheckedCast(mock(Logger.class));
+ }
+
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
}
@Test
- public void configureLogs_whenUnsupportedOperationExceptionIsThrown_withCause() {
- doThrow(new UnsupportedOperationException(
+ public void logsInfo_whenOperationIsSuccessful() throws UnableToSetSerialFilterException {
+ FilterConfiguration filterConfiguration = new GlobalSerialFilterConfiguration(
+ serializableObjectConfig,
+ logger,
+ (pattern, sanctionedClasses) -> globalSerialFilter);
+
+ filterConfiguration.configure();
+
+ verify(logger).info("Global serialization filter is now configured.");
+ verify(logger, never()).warn(any(Object.class));
+ verify(logger, never()).error(any(Object.class));
+ }
+
+ @Test
+ public void rethrowsWhenIllegalStateExceptionIsThrownByApi()
+ throws UnableToSetSerialFilterException {
+ doThrow(new UnableToSetSerialFilterException(
new IllegalStateException("Serial filter can only be set once")))
.when(globalSerialFilter).setFilter();
FilterConfiguration filterConfiguration = new GlobalSerialFilterConfiguration(
- config, logger, (pattern, sanctionedClasses) -> globalSerialFilter);
+ serializableObjectConfig,
+ (pattern, sanctionedClasses) -> globalSerialFilter);
- filterConfiguration.configure();
+ Throwable thrown = catchThrowable(() -> {
+ filterConfiguration.configure();
+ });
- verify(logger).accept("Global serial filter is already configured.");
+ assertThat(thrown)
+ .isInstanceOf(UnableToSetSerialFilterException.class)
+ .hasMessage("java.lang.IllegalStateException: Serial filter can only be set once")
+ .hasRootCauseInstanceOf(IllegalStateException.class)
+ .hasRootCauseMessage("Serial filter can only be set once");
}
@Test
- public void configureDoesNotLog_whenUnsupportedOperationExceptionIsThrown_withoutCause() {
- doThrow(new UnsupportedOperationException("testing with no root cause"))
- .when(globalSerialFilter).setFilter();
+ public void rethrowsWhenClassNotFoundExceptionIsThrownByApi()
+ throws UnableToSetSerialFilterException {
+ doThrow(new UnableToSetSerialFilterException(
+ new ClassNotFoundException("sun.misc.ObjectInputFilter")))
+ .when(globalSerialFilter).setFilter();
FilterConfiguration filterConfiguration = new GlobalSerialFilterConfiguration(
- config, logger, (pattern, sanctionedClasses) -> globalSerialFilter);
+ serializableObjectConfig,
+ (pattern, sanctionedClasses) -> globalSerialFilter);
- filterConfiguration.configure();
+ Throwable thrown = catchThrowable(() -> {
+ filterConfiguration.configure();
+ });
- verifyNoInteractions(logger);
+ assertThat(thrown)
+ .isInstanceOf(UnableToSetSerialFilterException.class)
+ .hasMessage("java.lang.ClassNotFoundException: sun.misc.ObjectInputFilter")
+ .hasRootCauseInstanceOf(ClassNotFoundException.class)
+ .hasRootCauseMessage("sun.misc.ObjectInputFilter");
}
@Test
- public void configureSetsValidateSerializableObjects() {
- SerializableObjectConfig serializableObjectConfig = mock(SerializableObjectConfig.class);
- FilterConfiguration filterConfiguration =
- new GlobalSerialFilterConfiguration(serializableObjectConfig);
+ public void setsValidateSerializableObjects() throws UnableToSetSerialFilterException {
+ FilterConfiguration filterConfiguration = new GlobalSerialFilterConfiguration(
+ serializableObjectConfig,
+ (pattern, sanctionedClasses) -> globalSerialFilter);
filterConfiguration.configure();
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactoryTest.java
index e7e72f6..53aa5b7 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactoryTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactoryTest.java
@@ -18,9 +18,13 @@ import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
import static org.apache.commons.lang3.JavaVersion.JAVA_9;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.RestoreSystemProperties;
@@ -30,6 +34,11 @@ public class JmxSerialFilterConfigurationFactoryTest {
@Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
+ }
+
@Test
public void createsConditionalJmxSerialFilterConfiguration_onJava9orGreater() {
assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationTest.java
index ad05630..75f1efd 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationTest.java
@@ -14,13 +14,16 @@
*/
package org.apache.geode.internal.serialization.filter;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import java.util.function.Consumer;
+import java.lang.reflect.InvocationTargetException;
+import org.apache.logging.log4j.Logger;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -31,7 +34,7 @@ public class JmxSerialFilterConfigurationTest {
private static final String SYSTEM_PROPERTY = "system.property.name";
private String pattern;
- private Consumer<String> loggerConsumer;
+ private Logger logger;
@Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
@@ -39,7 +42,12 @@ public class JmxSerialFilterConfigurationTest {
@Before
public void setUp() {
pattern = "the-filter-pattern";
- loggerConsumer = uncheckedCast(mock(Consumer.class));
+ logger = uncheckedCast(mock(Logger.class));
+ }
+
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
}
@Test
@@ -50,7 +58,7 @@ public class JmxSerialFilterConfigurationTest {
}
@Test
- public void setsPropertyValue() {
+ public void setsPropertyValue() throws UnableToSetSerialFilterException {
FilterConfiguration filterConfiguration =
new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
@@ -62,7 +70,7 @@ public class JmxSerialFilterConfigurationTest {
}
@Test
- public void setsPropertyValue_ifExistingValueIsNull() {
+ public void setsPropertyValue_ifExistingValueIsNull() throws UnableToSetSerialFilterException {
System.clearProperty(SYSTEM_PROPERTY);
FilterConfiguration filterConfiguration =
new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
@@ -75,7 +83,7 @@ public class JmxSerialFilterConfigurationTest {
}
@Test
- public void setsPropertyValue_ifExistingValueIsEmpty() {
+ public void setsPropertyValue_ifExistingValueIsEmpty() throws UnableToSetSerialFilterException {
System.setProperty(SYSTEM_PROPERTY, "");
FilterConfiguration filterConfiguration =
new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
@@ -88,7 +96,7 @@ public class JmxSerialFilterConfigurationTest {
}
@Test
- public void setsPropertyValue_ifExistingValueIsBlank() {
+ public void setsPropertyValue_ifExistingValueIsBlank() throws UnableToSetSerialFilterException {
System.setProperty(SYSTEM_PROPERTY, " ");
FilterConfiguration filterConfiguration =
new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
@@ -101,33 +109,34 @@ public class JmxSerialFilterConfigurationTest {
}
@Test
- public void logsNowConfigured_ifExistingValueIsEmpty() {
+ public void logsSuccess_ifExistingValueIsEmpty() throws UnableToSetSerialFilterException {
System.setProperty(SYSTEM_PROPERTY, "");
FilterConfiguration filterConfiguration =
- new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, loggerConsumer);
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, logger);
filterConfiguration.configure();
- verify(loggerConsumer)
- .accept("System property '" + SYSTEM_PROPERTY + "' is now configured with '" +
+ verify(logger)
+ .info("System property '" + SYSTEM_PROPERTY + "' is now configured with '" +
pattern + "'.");
}
@Test
- public void logsNowConfigured_ifExistingValueIsBlank() {
+ public void logsSuccess_ifExistingValueIsBlank() throws UnableToSetSerialFilterException {
System.setProperty(SYSTEM_PROPERTY, " ");
FilterConfiguration filterConfiguration =
- new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, loggerConsumer);
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, logger);
filterConfiguration.configure();
- verify(loggerConsumer)
- .accept("System property '" + SYSTEM_PROPERTY + "' is now configured with '" +
+ verify(logger)
+ .info("System property '" + SYSTEM_PROPERTY + "' is now configured with '" +
pattern + "'.");
}
@Test
- public void doesNotSetPropertyValue_ifExistingValueIsNotEmpty() {
+ public void doesNotSetPropertyValue_ifExistingValueIsNotEmpty()
+ throws UnableToSetSerialFilterException {
String existingValue = "existing-value-of-property";
System.setProperty(SYSTEM_PROPERTY, existingValue);
FilterConfiguration filterConfiguration =
@@ -141,15 +150,16 @@ public class JmxSerialFilterConfigurationTest {
}
@Test
- public void logsAlreadyConfiguredMessage_ifExistingPropertyValueIsNotEmpty() {
+ public void logsWarning_ifExistingPropertyValueIsNotEmpty()
+ throws UnableToSetSerialFilterException {
String existingValue = "existing-value-of-property";
System.setProperty(SYSTEM_PROPERTY, existingValue);
FilterConfiguration filterConfiguration =
- new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, loggerConsumer);
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, logger);
filterConfiguration.configure();
- verify(loggerConsumer)
- .accept("System property '" + SYSTEM_PROPERTY + "' is already configured.");
+ verify(logger)
+ .info("System property '" + SYSTEM_PROPERTY + "' is already configured.");
}
}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilterTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilterTest.java
index 2ab18a9..557dbdf 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilterTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilterTest.java
@@ -24,9 +24,9 @@ import org.junit.Test;
public class NullObjectInputFilterTest {
@Test
- public void doesNothing() {
+ public void doesNothing() throws UnableToSetSerialFilterException {
ObjectInputStream objectInputStream = mock(ObjectInputStream.class);
- ObjectInputFilter filter = new NullObjectInputFilter();
+ StreamSerialFilter filter = new NullStreamSerialFilter();
filter.setFilterOn(objectInputStream);
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterInvocationHandlerTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterInvocationHandlerTest.java
new file mode 100644
index 0000000..6248ea3
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterInvocationHandlerTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.serialization.filter;
+
+import static java.util.Collections.emptySet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ObjectInputFilterInvocationHandlerTest {
+
+ private static final String PATTERN = "*";
+
+ private Class<?> ObjectInputFilter;
+ private Method ObjectInputFilter_checkInput;
+ private Method ObjectInputFilter_FilterInfo_serialClass;
+ private Object ObjectInputFilter_Status_ALLOWED;
+ private Object ObjectInputFilter_Status_REJECTED;
+
+ private Object objectInputFilter;
+
+ @Before
+ public void setUp()
+ throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ ReflectiveObjectInputFilterApi api =
+ (ReflectiveObjectInputFilterApi) new ReflectiveObjectInputFilterApiFactory()
+ .createObjectInputFilterApi();
+
+ ObjectInputFilter = api.ObjectInputFilter;
+ ObjectInputFilter_checkInput = api.ObjectInputFilter_checkInput;
+ Class<?> objectInputFilter_Config = api.ObjectInputFilter_Config;
+ Method objectInputFilter_Config_createFilter = api.ObjectInputFilter_Config_createFilter;
+ ObjectInputFilter_Status_ALLOWED = api.ObjectInputFilter_Status_ALLOWED;
+ ObjectInputFilter_Status_REJECTED = api.ObjectInputFilter_Status_REJECTED;
+ ObjectInputFilter_FilterInfo_serialClass = api.ObjectInputFilter_FilterInfo_serialClass;
+
+ objectInputFilter = objectInputFilter_Config_createFilter
+ .invoke(objectInputFilter_Config, PATTERN);
+ }
+
+ @Test
+ public void sanctionedClassesIsRequired() {
+ Throwable thrown = catchThrowable(() -> {
+ new ObjectInputFilterInvocationHandler(
+ ObjectInputFilter_checkInput,
+ ObjectInputFilter_FilterInfo_serialClass,
+ ObjectInputFilter_Status_ALLOWED,
+ ObjectInputFilter_Status_REJECTED,
+ objectInputFilter,
+ null);
+ });
+
+ assertThat(thrown).isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void toStringIsInvokedOnProxiedInstance() {
+ InvocationHandler invocationHandler = new ObjectInputFilterInvocationHandler(
+ ObjectInputFilter_checkInput,
+ ObjectInputFilter_FilterInfo_serialClass,
+ ObjectInputFilter_Status_ALLOWED,
+ ObjectInputFilter_Status_REJECTED,
+ objectInputFilter,
+ emptySet());
+ Object proxy = objectInputFilterProxy(invocationHandler);
+
+ String result = proxy.toString();
+
+ assertThat(result).isEqualTo(PATTERN);
+ }
+
+ private Object objectInputFilterProxy(InvocationHandler invocationHandler) {
+ return Proxy.newProxyInstance(
+ getClass().getClassLoader(),
+ new Class[] {ObjectInputFilter},
+ invocationHandler);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactoryTest.java
index 34c83c4..844d0da 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactoryTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactoryTest.java
@@ -15,57 +15,62 @@
package org.apache.geode.internal.serialization.filter;
import static java.util.Collections.emptySet;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
+import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import java.lang.reflect.InvocationTargetException;
+import java.util.function.Supplier;
+import org.junit.After;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
public class ReflectiveFacadeGlobalSerialFilterFactoryTest {
- @Test
- public void constructsDelegatingGlobalSerialFilter() {
- ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
- GlobalSerialFilterFactory factory = new ReflectiveFacadeGlobalSerialFilterFactory(api);
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
- GlobalSerialFilter filter = factory.create("pattern", emptySet());
-
- assertThat(filter).isInstanceOf(ReflectiveFacadeGlobalSerialFilter.class);
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
}
+ /**
+ * Creates an instance of ReflectiveFacadeGlobalSerialFilter.
+ */
@Test
- public void delegatesToObjectInputFilterApiToCreateObjectInputFilter()
- throws InvocationTargetException, IllegalAccessException {
+ public void createsReflectiveFacadeGlobalSerialFilter() {
ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
GlobalSerialFilterFactory factory = new ReflectiveFacadeGlobalSerialFilterFactory(api);
- GlobalSerialFilter filter = factory.create("pattern", emptySet());
- Object objectInputFilter = mock(Object.class);
- when(api.createObjectInputFilterProxy(any(), any()))
- .thenReturn(objectInputFilter);
-
- filter.setFilter();
+ GlobalSerialFilter filter = factory.create("pattern", emptySet());
- verify(api).createObjectInputFilterProxy(any(), any());
+ assertThat(filter).isInstanceOf(ReflectiveFacadeGlobalSerialFilter.class);
}
+ /**
+ * Throws ClassNotFoundException nested inside an UnsupportedOperationException when the trying \
+ * to load the JDK ObjectInputFilter via reflection throws ClassNotFoundException.
+ */
@Test
- public void delegatesToObjectInputFilterApiToSetSerialFilter()
- throws InvocationTargetException, IllegalAccessException {
- ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
- GlobalSerialFilterFactory factory = new ReflectiveFacadeGlobalSerialFilterFactory(api);
- GlobalSerialFilter filter = factory.create("pattern", emptySet());
- Object objectInputFilter = mock(Object.class);
-
- when(api.createObjectInputFilterProxy(any(), any()))
- .thenReturn(objectInputFilter);
+ public void throws_whenObjectInputFilterClassNotFound() {
+ Supplier<ObjectInputFilterApi> objectInputFilterApiSupplier = () -> {
+ throw new UnsupportedOperationException("ObjectInputFilter is not available.",
+ new ClassNotFoundException("sun.misc.ObjectInputFilter"));
+ };
- filter.setFilter();
+ Throwable thrown = catchThrowable(() -> {
+ new ReflectiveFacadeGlobalSerialFilterFactory(objectInputFilterApiSupplier)
+ .create("pattern", emptySet());
+ });
- verify(api).setSerialFilter(objectInputFilter);
+ assertThat(thrown)
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessage("ObjectInputFilter is not available.")
+ .hasRootCauseInstanceOf(ClassNotFoundException.class)
+ .hasRootCauseMessage("sun.misc.ObjectInputFilter");
}
}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterTest.java
index 5966d1b..1635635 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterTest.java
@@ -15,20 +15,25 @@
package org.apache.geode.internal.serialization.filter;
import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentCaptor.forClass;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -36,19 +41,28 @@ import org.mockito.ArgumentCaptor;
public class ReflectiveFacadeGlobalSerialFilterTest {
private ObjectInputFilterApi api;
+ private Object objectInputFilter;
@Before
public void setUp() {
api = mock(ObjectInputFilterApi.class);
+ objectInputFilter = new Object();
+ }
+
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
}
@Test
public void createsObjectInputFilterProxy()
- throws InvocationTargetException, IllegalAccessException {
+ throws InvocationTargetException, IllegalAccessException, UnableToSetSerialFilterException {
String pattern = "the-pattern";
Collection<String> sanctionedClasses = asList("class-name-one", "class-name-two");
GlobalSerialFilter globalSerialFilter =
new ReflectiveFacadeGlobalSerialFilter(api, pattern, sanctionedClasses);
+ when(api.createObjectInputFilterProxy(eq("the-pattern"), anyCollection()))
+ .thenReturn(objectInputFilter);
globalSerialFilter.setFilter();
@@ -58,9 +72,12 @@ public class ReflectiveFacadeGlobalSerialFilterTest {
}
@Test
- public void setsSerialFilter() throws InvocationTargetException, IllegalAccessException {
+ public void setsSerialFilter()
+ throws InvocationTargetException, IllegalAccessException, UnableToSetSerialFilterException {
GlobalSerialFilter globalSerialFilter =
new ReflectiveFacadeGlobalSerialFilter(api, "the-pattern", singleton("class-name"));
+ when(api.createObjectInputFilterProxy(eq("the-pattern"), anyCollection()))
+ .thenReturn(objectInputFilter);
globalSerialFilter.setFilter();
@@ -68,37 +85,84 @@ public class ReflectiveFacadeGlobalSerialFilterTest {
}
@Test
- public void propagatesIllegalAccessExceptionInUnsupportedOperationException()
+ public void propagatesIllegalAccessExceptionInObjectInputFilterException()
throws InvocationTargetException, IllegalAccessException {
- IllegalAccessException exception = new IllegalAccessException("testing");
- doThrow(exception).when(api).setSerialFilter(any());
GlobalSerialFilter globalSerialFilter =
new ReflectiveFacadeGlobalSerialFilter(api, "the-pattern", singleton("class-name"));
+ IllegalAccessException illegalAccessException = new IllegalAccessException("testing");
+ when(api.createObjectInputFilterProxy(eq("the-pattern"), anyCollection()))
+ .thenReturn(objectInputFilter);
+ doThrow(illegalAccessException)
+ .when(api).setSerialFilter(any());
Throwable thrown = catchThrowable(() -> {
globalSerialFilter.setFilter();
});
assertThat(thrown)
- .isInstanceOf(UnsupportedOperationException.class)
- .hasRootCause(exception);
+ .isInstanceOf(UnableToSetSerialFilterException.class)
+ .hasMessage("Unable to configure a global serialization filter using reflection.")
+ .hasRootCause(illegalAccessException)
+ .hasRootCauseMessage("testing");
}
@Test
- public void propagatesInvocationTargetExceptionInUnsupportedOperationException()
+ public void propagatesInvocationTargetExceptionInObjectInputFilterException()
throws InvocationTargetException, IllegalAccessException {
- InvocationTargetException exception =
+ GlobalSerialFilter globalSerialFilter =
+ new ReflectiveFacadeGlobalSerialFilter(api, "the-pattern", singleton("class-name"));
+ InvocationTargetException invocationTargetException =
new InvocationTargetException(new Exception("testing"), "testing");
- doThrow(exception).when(api).setSerialFilter(any());
+ doThrow(invocationTargetException).when(api).setSerialFilter(any());
+
+ Throwable thrown = catchThrowable(() -> {
+ globalSerialFilter.setFilter();
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(UnableToSetSerialFilterException.class)
+ .hasMessage(
+ "Unable to configure a global serialization filter because invocation target threw "
+ + Exception.class.getName() + ".")
+ .hasCause(invocationTargetException)
+ .hasRootCauseInstanceOf(Exception.class)
+ .hasRootCauseMessage("testing");
+ }
+
+ /**
+ * The ObjectInputFilter API throws IllegalStateException nested within InvocationTargetException
+ * if a non-null filter already exists.
+ */
+ @Test
+ public void propagatesNestedIllegalStateExceptionInObjectInputFilterException()
+ throws InvocationTargetException, IllegalAccessException {
GlobalSerialFilter globalSerialFilter =
new ReflectiveFacadeGlobalSerialFilter(api, "the-pattern", singleton("class-name"));
+ InvocationTargetException invocationTargetException =
+ new InvocationTargetException(new IllegalStateException("testing"), "testing");
+ doThrow(invocationTargetException).when(api).setSerialFilter(any());
Throwable thrown = catchThrowable(() -> {
globalSerialFilter.setFilter();
});
assertThat(thrown)
- .isInstanceOf(UnsupportedOperationException.class)
- .hasCause(exception);
+ .isInstanceOf(FilterAlreadyConfiguredException.class)
+ .hasMessage(
+ "Unable to configure a global serialization filter because filter has already been set non-null.")
+ .hasCauseInstanceOf(InvocationTargetException.class)
+ .hasRootCauseInstanceOf(IllegalStateException.class)
+ .hasRootCauseMessage("testing");
+ }
+
+ @Test
+ public void requiresObjectInputFilterApi() {
+ Throwable thrown = catchThrowable(() -> {
+ new ReflectiveFacadeGlobalSerialFilter(null, "pattern", emptySet());
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(NullPointerException.class)
+ .hasMessage("ObjectInputFilterApi is required");
}
}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactoryTest.java
index e35b5bd..30c947b 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactoryTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactoryTest.java
@@ -48,10 +48,10 @@ public class ReflectiveFacadeObjectInputFilterFactoryTest {
assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
// arrange
- ObjectInputFilterFactory factory = new ReflectiveFacadeObjectInputFilterFactory();
+ StreamSerialFilterFactory factory = new ReflectiveFacadeStreamSerialFilterFactory();
// act
- ObjectInputFilter objectInputFilter = factory.create(config, SANCTIONED_CLASSES);
+ StreamSerialFilter objectInputFilter = factory.create(config, SANCTIONED_CLASSES);
// assert
assertThat(getApiPackage(getObjectInputFilterApi(objectInputFilter))).isEqualTo(JAVA_IO);
@@ -62,17 +62,17 @@ public class ReflectiveFacadeObjectInputFilterFactoryTest {
assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
// arrange
- ObjectInputFilterFactory factory = new ReflectiveFacadeObjectInputFilterFactory();
+ StreamSerialFilterFactory factory = new ReflectiveFacadeStreamSerialFilterFactory();
// act
- ObjectInputFilter objectInputFilter = factory.create(config, SANCTIONED_CLASSES);
+ StreamSerialFilter objectInputFilter = factory.create(config, SANCTIONED_CLASSES);
// assert
assertThat(getApiPackage(getObjectInputFilterApi(objectInputFilter))).isEqualTo(SUN_MISC);
}
- private static ObjectInputFilterApi getObjectInputFilterApi(ObjectInputFilter result) {
- ReflectiveFacadeObjectInputFilter impl = (ReflectiveFacadeObjectInputFilter) result;
+ private static ObjectInputFilterApi getObjectInputFilterApi(StreamSerialFilter result) {
+ ReflectiveFacadeStreamSerialFilter impl = (ReflectiveFacadeStreamSerialFilter) result;
ObjectInputFilterApi objectInputFilterApi = impl.getObjectInputFilterApi();
assertThat(objectInputFilterApi).isInstanceOf(ReflectiveObjectInputFilterApi.class);
return objectInputFilterApi;
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterTest.java
index cca697f..3976129 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterTest.java
@@ -50,11 +50,11 @@ public class ReflectiveFacadeObjectInputFilterTest {
@Test
public void createsObjectInputFilterProxy()
- throws InvocationTargetException, IllegalAccessException {
+ throws InvocationTargetException, IllegalAccessException, UnableToSetSerialFilterException {
String pattern = "the-pattern";
Collection<String> sanctionedClasses = asList("class-name-one", "class-name-two");
- ObjectInputFilter objectInputFilter =
- new ReflectiveFacadeObjectInputFilter(api, pattern, sanctionedClasses);
+ StreamSerialFilter objectInputFilter =
+ new ReflectiveFacadeStreamSerialFilter(api, pattern, sanctionedClasses);
objectInputFilter.setFilterOn(objectInputStream);
@@ -64,9 +64,10 @@ public class ReflectiveFacadeObjectInputFilterTest {
}
@Test
- public void setsSerialFilter() throws InvocationTargetException, IllegalAccessException {
- ObjectInputFilter objectInputFilter =
- new ReflectiveFacadeObjectInputFilter(api, "the-pattern", singleton("class-name"));
+ public void setsSerialFilter()
+ throws InvocationTargetException, IllegalAccessException, UnableToSetSerialFilterException {
+ StreamSerialFilter objectInputFilter =
+ new ReflectiveFacadeStreamSerialFilter(api, "the-pattern", singleton("class-name"));
objectInputFilter.setFilterOn(objectInputStream);
@@ -76,43 +77,75 @@ public class ReflectiveFacadeObjectInputFilterTest {
@Test
public void propagatesIllegalAccessExceptionInUnsupportedOperationException()
throws InvocationTargetException, IllegalAccessException {
- IllegalAccessException exception = new IllegalAccessException("testing");
- doThrow(exception).when(api).setObjectInputFilter(same(objectInputStream), any());
- ObjectInputFilter objectInputFilter =
- new ReflectiveFacadeObjectInputFilter(api, "the-pattern", singleton("class-name"));
+ IllegalAccessException illegalAccessException = new IllegalAccessException("testing");
+ doThrow(illegalAccessException).when(api).setObjectInputFilter(same(objectInputStream), any());
+ StreamSerialFilter objectInputFilter =
+ new ReflectiveFacadeStreamSerialFilter(api, "the-pattern", singleton("class-name"));
Throwable thrown = catchThrowable(() -> {
objectInputFilter.setFilterOn(objectInputStream);
});
assertThat(thrown)
- .isInstanceOf(UnsupportedOperationException.class)
- .hasRootCause(exception);
+ .isInstanceOf(UnableToSetSerialFilterException.class)
+ .hasMessage("Unable to configure an input stream serialization filter using reflection.")
+ .hasRootCause(illegalAccessException);
}
@Test
public void propagatesInvocationTargetExceptionInUnsupportedOperationException()
throws InvocationTargetException, IllegalAccessException {
- InvocationTargetException exception =
+ InvocationTargetException invocationTargetException =
new InvocationTargetException(new Exception("testing"), "testing");
- doThrow(exception).when(api).setObjectInputFilter(same(objectInputStream), any());
- ObjectInputFilter objectInputFilter =
- new ReflectiveFacadeObjectInputFilter(api, "the-pattern", singleton("class-name"));
+ doThrow(invocationTargetException).when(api).setObjectInputFilter(same(objectInputStream),
+ any());
+ StreamSerialFilter objectInputFilter =
+ new ReflectiveFacadeStreamSerialFilter(api, "the-pattern", singleton("class-name"));
Throwable thrown = catchThrowable(() -> {
objectInputFilter.setFilterOn(objectInputStream);
});
assertThat(thrown)
- .isInstanceOf(UnsupportedOperationException.class)
- .hasCause(exception);
+ .isInstanceOf(UnableToSetSerialFilterException.class)
+ .hasMessage(
+ "Unable to configure an input stream serialization filter because invocation target threw "
+ + Exception.class.getName() + ".")
+ .hasCause(invocationTargetException);
}
+ /**
+ * The ObjectInputFilter API throws IllegalStateException nested within InvocationTargetException
+ * if a non-null filter already exists.
+ */
@Test
- public void delegatesToObjectInputFilterApiToCreateObjectInputFilter()
+ public void propagatesNestedIllegalStateExceptionInObjectInputFilterException()
throws InvocationTargetException, IllegalAccessException {
+ StreamSerialFilter objectInputFilter =
+ new ReflectiveFacadeStreamSerialFilter(api, "the-pattern", singleton("class-name"));
+ InvocationTargetException invocationTargetException =
+ new InvocationTargetException(new IllegalStateException("testing"), "testing");
+ doThrow(invocationTargetException)
+ .when(api).setObjectInputFilter(same(objectInputStream), any());
+
+ Throwable thrown = catchThrowable(() -> {
+ objectInputFilter.setFilterOn(objectInputStream);
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(FilterAlreadyConfiguredException.class)
+ .hasMessage(
+ "Unable to configure an input stream serialization filter because a non-null filter has already been set.")
+ .hasCauseInstanceOf(InvocationTargetException.class)
+ .hasRootCauseInstanceOf(IllegalStateException.class)
+ .hasRootCauseMessage("testing");
+ }
+
+ @Test
+ public void delegatesToObjectInputFilterApiToCreateObjectInputFilter()
+ throws InvocationTargetException, IllegalAccessException, UnableToSetSerialFilterException {
ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
- ObjectInputFilter filter = new ReflectiveFacadeObjectInputFilter(api, "pattern", emptySet());
+ StreamSerialFilter filter = new ReflectiveFacadeStreamSerialFilter(api, "pattern", emptySet());
Object objectInputFilter = mock(Object.class);
ObjectInputStream objectInputStream = mock(ObjectInputStream.class);
@@ -126,9 +159,9 @@ public class ReflectiveFacadeObjectInputFilterTest {
@Test
public void delegatesToObjectInputFilterApiToSetFilterOnObjectInputStream()
- throws InvocationTargetException, IllegalAccessException {
+ throws InvocationTargetException, IllegalAccessException, UnableToSetSerialFilterException {
ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
- ObjectInputFilter filter = new ReflectiveFacadeObjectInputFilter(api, "pattern", emptySet());
+ StreamSerialFilter filter = new ReflectiveFacadeStreamSerialFilter(api, "pattern", emptySet());
Object objectInputFilter = mock(Object.class);
ObjectInputStream objectInputStream = mock(ObjectInputStream.class);
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactoryTest.java
index b3ac61f..a1eb877 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactoryTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactoryTest.java
@@ -18,13 +18,22 @@ import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
import static org.apache.commons.lang3.JavaVersion.JAVA_9;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.After;
import org.junit.Test;
public class ReflectiveObjectInputFilterApiFactoryTest {
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
+ }
+
@Test
public void createsInstanceOfReflectionObjectInputFilterApi() {
ObjectInputFilterApiFactory factory = new ReflectiveObjectInputFilterApiFactory();
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiTest.java
index 8cf1f8c..b456eb3 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiTest.java
@@ -22,6 +22,7 @@ import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
import static org.apache.commons.lang3.JavaVersion.JAVA_9;
import static org.apache.commons.lang3.SerializationUtils.serialize;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
@@ -32,6 +33,7 @@ import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -48,6 +50,11 @@ public class ReflectiveObjectInputFilterApiTest {
}
}
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
+ }
+
@Test
public void createFilterGivenValidPatternReturnsNewFilter()
throws IllegalAccessException, InvocationTargetException {
@@ -89,9 +96,7 @@ public class ReflectiveObjectInputFilterApiTest {
Object filter = api.getSerialFilter();
- assertThat(filter)
- .as("ObjectInputFilter$Config.getSerialFilter()")
- .isNull();
+ assertThat(filter).isNull();
}
@Test
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
similarity index 52%
copy from geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
copy to geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
index b6d552a..760e391 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
@@ -14,12 +14,14 @@
*/
package org.apache.geode.internal.serialization.filter;
+import static java.lang.System.lineSeparator;
+import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace;
import static org.assertj.core.api.Assertions.assertThat;
import java.lang.reflect.InvocationTargetException;
-@SuppressWarnings({"unused", "WeakerAccess"})
-public class SerialFilterAssertions {
+@SuppressWarnings("unused")
+class SerialFilterAssertions {
private static final ObjectInputFilterApi API = new ReflectiveObjectInputFilterApiFactory()
.createObjectInputFilterApi();
@@ -28,37 +30,40 @@ public class SerialFilterAssertions {
// do not instantiate
}
- public static void assertThatSerialFilterIsNull()
+ static void assertThatSerialFilterIsNull()
throws InvocationTargetException, IllegalAccessException {
- boolean exists = API.getSerialFilter() != null;
- assertThat(exists)
- .as("ObjectInputFilter$Config.getSerialFilter() is null")
- .isFalse();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isNull();
}
- public static void assertThatSerialFilterIsNotNull()
+ static void assertThatSerialFilterIsNotNull()
throws InvocationTargetException, IllegalAccessException {
- boolean exists = API.getSerialFilter() != null;
- assertThat(exists)
- .as("ObjectInputFilter$Config.getSerialFilter() is not null")
- .isTrue();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isNotNull();
}
- public static void assertThatSerialFilterIsSameAs(Object objectInputFilter)
+ static void assertThatSerialFilterIsSameAs(Object objectInputFilter)
throws InvocationTargetException, IllegalAccessException {
- Object currentFilter = API.getSerialFilter();
- boolean sameIdentity = currentFilter == objectInputFilter;
- assertThat(sameIdentity)
- .as("ObjectInputFilter$Config.getSerialFilter() is same as parameter")
- .isTrue();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isSameAs(objectInputFilter);
}
- public static void assertThatSerialFilterIsNotSameAs(Object objectInputFilter)
+ static void assertThatSerialFilterIsNotSameAs(Object objectInputFilter)
throws InvocationTargetException, IllegalAccessException {
- Object currentFilter = API.getSerialFilter();
- boolean sameIdentity = currentFilter == objectInputFilter;
- assertThat(sameIdentity)
- .as("ObjectInputFilter$Config.getSerialFilter() is same as parameter")
- .isFalse();
+ assertThat(API.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isNotSameAs(objectInputFilter);
+ }
+
+ static String failMessageWithStackTraces(String message, Iterable<Throwable> stackTraces) {
+ StringBuilder formattedStackTraces = new StringBuilder(message);
+ for (Throwable stackTrace : stackTraces) {
+ formattedStackTraces.append(lineSeparator());
+ formattedStackTraces.append(getStackTrace(stackTrace));
+ }
+ return formattedStackTraces.toString();
}
}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactoryTest.java
index 45070a6..0d01e7a 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactoryTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactoryTest.java
@@ -14,62 +14,131 @@
*/
package org.apache.geode.internal.serialization.filter;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.Mockito.mock;
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.RestoreSystemProperties;
public class SystemPropertyGlobalSerialFilterConfigurationFactoryTest {
+ private SerializableObjectConfig config;
+
@Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+ @Before
+ public void setUp() {
+ config = mock(SerializableObjectConfig.class);
+ }
+
+ @After
+ public void serialFilterIsNull() throws InvocationTargetException, IllegalAccessException {
+ assertThatSerialFilterIsNull();
+ }
+
@Test
- public void createsConditionalGlobalSerialFilterConfiguration_whenEnableGlobalSerialFilter_isSet() {
- System.setProperty("geode.enableGlobalSerialFilter", "true");
+ public void createsNoOp_whenEnableGlobalSerialFilterIsFalse()
+ throws UnableToSetSerialFilterException {
+ System.clearProperty("geode.enableGlobalSerialFilter");
GlobalSerialFilterConfigurationFactory factory =
new SystemPropertyGlobalSerialFilterConfigurationFactory();
- FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+ FilterConfiguration configuration = factory.create(config);
- assertThat(filterConfiguration).isInstanceOf(GlobalSerialFilterConfiguration.class);
+ boolean result = configuration.configure();
+
+ assertThat(result).isFalse();
}
@Test
- public void createsNoOp_whenEnableGlobalSerialFilter_isNotSet() {
+ public void createsEnabledGlobalSerialFilterConfiguration_whenEnableGlobalSerialFilterIsTrue() {
+ System.setProperty("geode.enableGlobalSerialFilter", "true");
GlobalSerialFilterConfigurationFactory factory =
new SystemPropertyGlobalSerialFilterConfigurationFactory();
- FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+ FilterConfiguration configuration = factory.create(config);
- assertThat(filterConfiguration)
- .isNotInstanceOf(GlobalSerialFilterConfiguration.class);
+ // don't actually invoke configure because this is a unit test
+ assertThat(configuration).isInstanceOf(GlobalSerialFilterConfiguration.class);
}
@Test
- public void createsNoOp_whenJdkSerialFilter_isSet() {
+ public void createsNoOp_whenJdkSerialFilterExists() throws UnableToSetSerialFilterException {
System.setProperty("jdk.serialFilter", "*");
GlobalSerialFilterConfigurationFactory factory =
new SystemPropertyGlobalSerialFilterConfigurationFactory();
- FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+ FilterConfiguration configuration = factory.create(config);
- assertThat(filterConfiguration)
- .isNotInstanceOf(GlobalSerialFilterConfiguration.class);
+ boolean result = configuration.configure();
+
+ assertThat(result).isFalse();
}
@Test
- public void createsNoOp_whenJdkSerialFilter_andEnableGlobalSerialFilter_areBothSet() {
+ public void createsNoOp_whenJdkSerialFilterExists_andEnableGlobalSerialFilterIsTrue()
+ throws UnableToSetSerialFilterException {
System.setProperty("jdk.serialFilter", "*");
System.setProperty("geode.enableGlobalSerialFilter", "true");
GlobalSerialFilterConfigurationFactory factory =
new SystemPropertyGlobalSerialFilterConfigurationFactory();
- FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+ FilterConfiguration configuration = factory.create(config);
+
+ boolean result = configuration.configure();
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void createsNoOp_whenEnableGlobalSerialFilterIsFalse_andJreDoesNotSupportObjectInputFilter()
+ throws UnableToSetSerialFilterException {
+ boolean supportsObjectInputFilter = false;
+ GlobalSerialFilterConfigurationFactory configurationFactory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory(() -> supportsObjectInputFilter);
+
+ FilterConfiguration configuration = configurationFactory.create(config);
+
+ boolean result = configuration.configure();
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void createsNoOp_whenEnableGlobalSerialFilterIsTrue_andJreDoesNotSupportObjectInputFilter()
+ throws UnableToSetSerialFilterException {
+ System.setProperty("geode.enableGlobalSerialFilter", "true");
+ boolean supportsObjectInputFilter = false;
+ GlobalSerialFilterConfigurationFactory configurationFactory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory(() -> supportsObjectInputFilter);
+
+ FilterConfiguration configuration = configurationFactory.create(config);
+
+ boolean result = configuration.configure();
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void doesNotThrow_whenEnableGlobalSerialFilterIsFalse_andJreDoesNotSupportObjectInputFilter() {
+ System.clearProperty("geode.enableGlobalSerialFilter");
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory();
+
+ assertThatCode(() -> {
+
+ FilterConfiguration configuration = factory.create(config);
+
+ configuration.configure();
- assertThat(filterConfiguration)
- .isNotInstanceOf(GlobalSerialFilterConfiguration.class);
+ }).doesNotThrowAnyException();
}
}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactoryTest.java
index d95ef9c..76a9a51 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactoryTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactoryTest.java
@@ -46,7 +46,8 @@ public class SystemPropertyJmxSerialFilterConfigurationFactoryTest {
}
@Test
- public void returnsEnabledConfiguration_whenFilteringIsEnabled() {
+ public void returnsEnabledConfiguration_whenFilteringIsEnabled()
+ throws UnableToSetSerialFilterException {
JmxSerialFilterConfigurationFactory factory =
new SystemPropertyJmxSerialFilterConfigurationFactory(true, PATTERN);
@@ -56,7 +57,8 @@ public class SystemPropertyJmxSerialFilterConfigurationFactoryTest {
}
@Test
- public void returnsDisabledConfiguration_whenFilteringIsDisabled() {
+ public void returnsDisabledConfiguration_whenFilteringIsDisabled()
+ throws UnableToSetSerialFilterException {
JmxSerialFilterConfigurationFactory factory =
new SystemPropertyJmxSerialFilterConfigurationFactory(false, PATTERN);
@@ -66,7 +68,8 @@ public class SystemPropertyJmxSerialFilterConfigurationFactoryTest {
}
@Test
- public void enabledConfiguration_setsJmxSerialFilterProperty() {
+ public void enabledConfiguration_setsJmxSerialFilterProperty()
+ throws UnableToSetSerialFilterException {
JmxSerialFilterConfigurationFactory factory =
new SystemPropertyJmxSerialFilterConfigurationFactory(true, PATTERN);
FilterConfiguration filterConfiguration = factory.create();
@@ -77,7 +80,8 @@ public class SystemPropertyJmxSerialFilterConfigurationFactoryTest {
}
@Test
- public void disabledConfiguration_doesNotSetAnySystemProperties() {
+ public void disabledConfiguration_doesNotSetAnySystemProperties()
+ throws UnableToSetSerialFilterException {
Map<?, ?> propertiesBefore = System.getProperties();
JmxSerialFilterConfigurationFactory factory =
new SystemPropertyJmxSerialFilterConfigurationFactory(true, PATTERN);