You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by mk...@apache.org on 2020/12/03 07:24:39 UTC
[geode] branch develop updated: GEODE-8687: Fix for handling of
PdxSerializationException on client (#5730)
This is an automated email from the ASF dual-hosted git repository.
mkevo pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 2e7e456 GEODE-8687: Fix for handling of PdxSerializationException on client (#5730)
2e7e456 is described below
commit 2e7e45699b74812038dc516aaf7c14621951090b
Author: Jakov Varenina <62...@users.noreply.github.com>
AuthorDate: Thu Dec 3 08:23:54 2020 +0100
GEODE-8687: Fix for handling of PdxSerializationException on client (#5730)
* GEODE-8687: Improve handling of seralization error
* Improves handling of PdxSerializationException on client at the reception
of events from subscription queue
* Faulty behavior: At the reception of event for which
PdxSerializationException is thrown the client would always shutdown
CacheClientUpdater, destroy subscription queue connection
and try to perform failover to other server in cluster
* Behaviour with this fix: At the reception of event that provoke
PdxSerializationException client will only log the exception
* DurableClientCQAutoSerializer test updated
* Empty commit to trigger test
* Updates after review
---
.../cache/tier/sockets/CacheClientUpdater.java | 3 +-
.../DurableClientCQAutoSerializerDUnitTest.java | 289 +++++++++++++++++++++
.../tier/sockets/TestAutoSerializerCqListener.java | 57 ++++
.../tier/sockets/TestAutoSerializerObject1.java | 110 ++++++++
.../tier/sockets/TestAutoSerializerObject2.java | 109 ++++++++
5 files changed, 567 insertions(+), 1 deletion(-)
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientUpdater.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientUpdater.java
index 9690503..cedd92d 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientUpdater.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientUpdater.java
@@ -87,6 +87,7 @@ import org.apache.geode.internal.serialization.KnownVersion;
import org.apache.geode.internal.statistics.StatisticsTypeFactoryImpl;
import org.apache.geode.logging.internal.executors.LoggingThread;
import org.apache.geode.logging.internal.log4j.api.LogService;
+import org.apache.geode.pdx.PdxSerializationException;
import org.apache.geode.security.AuthenticationFailedException;
import org.apache.geode.security.AuthenticationRequiredException;
import org.apache.geode.security.GemFireSecurityException;
@@ -1793,7 +1794,7 @@ public class CacheClientUpdater extends LoggingThread implements ClientUpdater,
// This is a debugging method so ignore all exceptions like ClassNotFoundException
try (ByteArrayDataInput dis = new ByteArrayDataInput(serializedBytes)) {
deserializedObject = DataSerializer.readObject(dis);
- } catch (ClassNotFoundException | IOException ignore) {
+ } catch (ClassNotFoundException | IOException | PdxSerializationException e) {
}
return deserializedObject;
}
diff --git a/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/DurableClientCQAutoSerializerDUnitTest.java b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/DurableClientCQAutoSerializerDUnitTest.java
new file mode 100644
index 0000000..85b7919
--- /dev/null
+++ b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/DurableClientCQAutoSerializerDUnitTest.java
@@ -0,0 +1,289 @@
+/*
+ * 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.cache.tier.sockets;
+
+import static org.apache.geode.cache.Region.SEPARATOR;
+import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Objects;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientRegionFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+import org.apache.geode.cache.client.internal.PoolImpl;
+import org.apache.geode.cache.query.CqAttributesFactory;
+import org.apache.geode.cache.query.CqQuery;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.internal.cache.CacheServerImpl;
+import org.apache.geode.pdx.ReflectionBasedAutoSerializer;
+import org.apache.geode.pdx.internal.AutoSerializableManager;
+import org.apache.geode.test.dunit.Invoke;
+import org.apache.geode.test.dunit.rules.ClientVM;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.ClientSubscriptionTest;
+import org.apache.geode.test.junit.categories.SerializationTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+@Category({ClientSubscriptionTest.class, SerializationTest.class})
+public class DurableClientCQAutoSerializerDUnitTest implements Serializable {
+ private static final String REPLICATE_REGION_NAME = "ReplicateRegion";
+ private static final String PARTITION_REGION_NAME = "PartitionRegion";
+
+ private MemberVM server;
+ private MemberVM server2;
+ private MemberVM locator;
+ private ClientVM client;
+ private ClientVM client2;
+
+ private static TestAutoSerializerCqListener cqListener = null;
+
+ private static final String TEST_OBJECT1_CLASS_PATH =
+ "org.apache.geode.internal.cache.tier.sockets.TestAutoSerializerObject1";
+ private static final String TEST_OBJECT2_CLASS_PATH =
+ "org.apache.geode.internal.cache.tier.sockets.TestAutoSerializerObject2";
+ private static final String TEST_FAULTY_CLASS_PATH =
+ "org.apache.geode.internal.cache.tier.sockets.TestAutoSerializerObject2Faulty";
+ private static final String DURABLE_CLIENT_ID = "durableClient";
+
+ // Traffic data
+ static final Map<String, TestAutoSerializerObject1> LIST_TEST_OBJECT1 = ImmutableMap.of(
+ "key1", new TestAutoSerializerObject1("aa", "bb", 300),
+ "key2", new TestAutoSerializerObject1("aa", "bb", 600),
+ "key3", new TestAutoSerializerObject1("aaa", "bbb", 500));
+
+ static final Map<String, TestAutoSerializerObject2> LIST_TEST_OBJECT2 = ImmutableMap.of(
+ "key1", new TestAutoSerializerObject2("cc", "ddd", 300),
+ "key2", new TestAutoSerializerObject2("cc", "dddd", 400));
+
+ @Rule
+ public GfshCommandRule gfsh = new GfshCommandRule();
+
+ @Rule
+ public ClusterStartupRule cluster = new ClusterStartupRule(5);
+
+ @Before
+ public void setUp() throws Exception {
+ Invoke.invokeInEveryVM(
+ () -> System.setProperty(AutoSerializableManager.NO_HARDCODED_EXCLUDES_PARAM, "true"));
+
+ locator =
+ cluster.startLocatorVM(0);
+ int locatorPort = locator.getPort();
+ server = cluster.startServerVM(1,
+ s -> s.withConnectionToLocator(locatorPort));
+
+ server2 = cluster.startServerVM(2,
+ s -> s.withConnectionToLocator(locatorPort));
+
+ gfsh.connectAndVerify(locator);
+ gfsh.executeAndAssertThat(
+ "configure pdx --auto-serializable-classes='" + TEST_OBJECT1_CLASS_PATH + ", "
+ + TEST_OBJECT2_CLASS_PATH + "'")
+ .statusIsSuccess();
+ gfsh.executeAndAssertThat("create region --name=" + REPLICATE_REGION_NAME + " --type=REPLICATE")
+ .statusIsSuccess();
+ gfsh.executeAndAssertThat("create region --name=" + PARTITION_REGION_NAME + " --type=PARTITION")
+ .statusIsSuccess();
+
+ locator.invoke(() -> {
+ ClusterStartupRule.memberStarter
+ .waitUntilRegionIsReadyOnExactlyThisManyServers(SEPARATOR + REPLICATE_REGION_NAME, 2);
+ ClusterStartupRule.memberStarter
+ .waitUntilRegionIsReadyOnExactlyThisManyServers(SEPARATOR + PARTITION_REGION_NAME, 2);
+ });
+ }
+
+ @Test
+ public void testCorrectClassPathsAutoSerializer()
+ throws Exception {
+
+ String query1 = "SELECT * FROM " + SEPARATOR + REPLICATE_REGION_NAME;
+ String query2 = "SELECT * FROM " + SEPARATOR + PARTITION_REGION_NAME;
+
+ startDurableClient(TEST_OBJECT1_CLASS_PATH, TEST_OBJECT2_CLASS_PATH);
+ createDurableCQs(query1, query2);
+ verifyThatOnlyOneServerHostDurableSubscription();
+
+ // Start another client and provision data with traffic that should trigger CQs
+ startDataProvisionClient(TEST_OBJECT1_CLASS_PATH, TEST_OBJECT2_CLASS_PATH);
+ provisionRegionsWithData();
+
+ // Check that all events are received and successfully deserialized in cq listener
+ checkCqEvents(LIST_TEST_OBJECT1.size(), LIST_TEST_OBJECT2.size());
+ verifyThatOnlyOneServerHostDurableSubscription();
+ }
+
+ @Test
+ public void testFaultyClassPathAutoSerializer()
+ throws Exception {
+ String query1 = "SELECT * FROM " + SEPARATOR + REPLICATE_REGION_NAME;
+ String query2 = "SELECT * FROM " + SEPARATOR + PARTITION_REGION_NAME;
+ startDurableClient(TEST_FAULTY_CLASS_PATH, TEST_OBJECT2_CLASS_PATH);
+ createDurableCQs(query1, query2);
+ verifyThatOnlyOneServerHostDurableSubscription();
+
+ // Start another client and provision data with traffic that should trigger CQs
+ startDataProvisionClient(TEST_OBJECT1_CLASS_PATH, TEST_OBJECT2_CLASS_PATH);
+ provisionRegionsWithData();
+
+ // Check that only events for which ReflectionBasedAutoSerializer is correctly set are received
+ // and successfully deserialized in cq listener
+ checkCqEvents(0, LIST_TEST_OBJECT2.size());
+ verifyThatOnlyOneServerHostDurableSubscription();
+ }
+
+ private void startDataProvisionClient(String... patterns) throws Exception {
+ int locatorPort = locator.getPort();
+ client2 = cluster.startClientVM(4, ccf -> ccf
+ .withLocatorConnection(locatorPort).withCacheSetup(c -> c
+ .setPdxSerializer(new ReflectionBasedAutoSerializer(patterns))));
+ }
+
+ private void startDurableClient(String... patterns)
+ throws Exception {
+ int locatorPort = locator.getPort();
+ client = cluster.startClientVM(3, ccf -> ccf
+ .withPoolSubscription(true).withLocatorConnection(locatorPort).withCacheSetup(c -> c
+ .setPdxSerializer(new ReflectionBasedAutoSerializer(patterns))
+ .set("durable-client-id", DURABLE_CLIENT_ID)));
+ }
+
+ private void createDurableCQs(String... queries) {
+ client.invoke(() -> {
+ TestAutoSerializerCqListener cqListener = new TestAutoSerializerCqListener();
+ DurableClientCQAutoSerializerDUnitTest.cqListener = cqListener;
+ assertThat(ClusterStartupRule.getClientCache()).isNotNull();
+ QueryService queryService = ClusterStartupRule.getClientCache().getQueryService();
+ CqAttributesFactory cqAttributesFactory = new CqAttributesFactory();
+ cqAttributesFactory.addCqListener(cqListener);
+
+ for (String query : queries) {
+ CqQuery cq = queryService.newCq(query, cqAttributesFactory.create(), true);
+ cq.execute();
+ }
+ ClusterStartupRule.getClientCache().readyForEvents();
+ });
+ }
+
+ boolean isPrimaryServer(int primaryPort, MemberVM member) {
+ return primaryPort == member.getPort();
+ }
+
+ private void verifyThatOnlyOneServerHostDurableSubscription() {
+ int primPort = getPrimaryServerPort(client);
+ verifyDurableClientPresence(server, isPrimaryServer(primPort, server));
+ verifyDurableClientPresence(server2, isPrimaryServer(primPort, server2));
+ }
+
+ private void checkCqEvents(int expectedTestAutoSerializerObject1,
+ int expectedTestAutoSerializerObject2) {
+ // Check if number of events is correct
+ client.invoke(() -> {
+ await().untilAsserted(() -> assertThat(
+ DurableClientCQAutoSerializerDUnitTest.cqListener.getNumEvents())
+ .isEqualTo(expectedTestAutoSerializerObject1 + expectedTestAutoSerializerObject2));
+
+ // Check if events are deserialized correctly
+ if (expectedTestAutoSerializerObject1 != 0) {
+ assertEquals(DurableClientCQAutoSerializerDUnitTest.cqListener.testAutoSerializerObject1,
+ LIST_TEST_OBJECT1);
+ }
+ if (expectedTestAutoSerializerObject2 != 0) {
+ assertEquals(DurableClientCQAutoSerializerDUnitTest.cqListener.testAutoSerializerObject2,
+ LIST_TEST_OBJECT2);
+ }
+ });
+ }
+
+ private void verifyDurableClientPresence(MemberVM serverVM, boolean isExpected) {
+ serverVM.invoke(() -> {
+ await()
+ .until(() -> isExpected == (getNumberOfClientProxies() == 1));
+
+ if (isExpected) {
+ // Get the CacheClientProxy or not (if proxy set is empty)
+ CacheClientProxy proxy = getClientProxy();
+ assertThat(proxy).isNotNull();
+ // Verify that it is durable and its properties are correct
+ assertThat(proxy.isDurable()).isTrue();
+ assertThat(DURABLE_CLIENT_ID).isEqualTo(proxy.getDurableId());
+ }
+ });
+ }
+
+ private static CacheClientProxy getClientProxy() {
+ // Get the CacheClientProxy or not (if proxy set is empty)
+ CacheClientProxy proxy = null;
+ java.util.Iterator<CacheClientProxy> i = getCacheClientNotifier().getClientProxies().iterator();
+ if (i.hasNext()) {
+ proxy = i.next();
+ }
+ return proxy;
+ }
+
+ private static CacheClientNotifier getCacheClientNotifier() {
+ // Get the CacheClientNotifier
+ CacheServerImpl cacheServer = (CacheServerImpl) Objects
+ .requireNonNull(ClusterStartupRule.getCache()).getCacheServers().iterator().next();
+ assertNotNull(cacheServer);
+
+ // Get the CacheClientNotifier
+ return cacheServer.getAcceptor().getCacheClientNotifier();
+ }
+
+ private static int getNumberOfClientProxies() {
+ return getCacheClientNotifier().getClientProxies().size();
+ }
+
+ private void provisionRegionsWithData() {
+ client2.invoke(() -> {
+ ClientRegionFactory factory =
+ ClusterStartupRule.getClientCache().createClientRegionFactory(ClientRegionShortcut.PROXY);
+ Region<String, TestAutoSerializerObject1> region = factory.create(REPLICATE_REGION_NAME);
+
+ // provision TestAutoSerializerObject1 data
+ for (Map.Entry<String, TestAutoSerializerObject1> entry : LIST_TEST_OBJECT1.entrySet()) {
+ region.put(entry.getKey(), entry.getValue());
+ }
+
+ Region<String, TestAutoSerializerObject2> region2 = factory.create(PARTITION_REGION_NAME);
+ // provision TestAutoSerializerObject2 data
+ for (Map.Entry<String, TestAutoSerializerObject2> entry : LIST_TEST_OBJECT2.entrySet()) {
+ region2.put(entry.getKey(), entry.getValue());
+ }
+ });
+ }
+
+ private int getPrimaryServerPort(ClientVM client) {
+ return client.invoke(() -> {
+ ClientCache cache = ClusterStartupRule.getClientCache();
+ PoolImpl pool = (PoolImpl) cache.getDefaultPool();
+ return pool.getPrimaryPort();
+ });
+ }
+}
diff --git a/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerCqListener.java b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerCqListener.java
new file mode 100644
index 0000000..70de415
--- /dev/null
+++ b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerCqListener.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.cache.tier.sockets;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.geode.cache.query.CqEvent;
+import org.apache.geode.cache.query.CqListener;
+
+public class TestAutoSerializerCqListener implements CqListener {
+ private int numEvents = 0;
+ private int numErrors = 0;
+ public Map<String, TestAutoSerializerObject1> testAutoSerializerObject1 = new HashMap<>();
+ public Map<String, TestAutoSerializerObject2> testAutoSerializerObject2 = new HashMap<>();
+
+ public int getNumEvents() {
+ return numEvents;
+ }
+
+ public int getNumErrors() {
+ return numErrors;
+ }
+
+ @Override
+ public void onEvent(CqEvent aCqEvent) {
+ Object obj = aCqEvent.getNewValue();
+ if (obj instanceof TestAutoSerializerObject1) {
+ testAutoSerializerObject1.put((String) aCqEvent.getKey(),
+ (TestAutoSerializerObject1) aCqEvent.getNewValue());
+ } else if (obj instanceof TestAutoSerializerObject2) {
+ testAutoSerializerObject2.put((String) aCqEvent.getKey(),
+ (TestAutoSerializerObject2) aCqEvent.getNewValue());
+ }
+ numEvents++;
+ }
+
+ @Override
+ public void onError(CqEvent aCqEvent) {
+ numErrors++;
+ }
+
+ @Override
+ public void close() {}
+}
diff --git a/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerObject1.java b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerObject1.java
new file mode 100644
index 0000000..8cc85e5
--- /dev/null
+++ b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerObject1.java
@@ -0,0 +1,110 @@
+/*
+ * 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.cache.tier.sockets;
+
+import java.util.Objects;
+
+import org.apache.geode.internal.PdxSerializerObject;
+
+/**
+ * <strong>Explicitly</strong> not serializable by java.io.Serializable,
+ * org.apache.geode.DataSerializable, or org.apache.geode.pdx.PdxSerializable.
+ */
+public class TestAutoSerializerObject1 implements PdxSerializerObject {
+ protected String data1;
+ protected String data2;
+ protected int numData;
+
+ public TestAutoSerializerObject1() {
+ this("", "", 0);
+ }
+
+ protected TestAutoSerializerObject1(String data1, String data2, int numData) {
+ this.data1 = data1;
+ this.data2 = data2;
+ this.numData = numData;
+ }
+
+ public String getData1() {
+ return data1;
+ }
+
+ public String getData2() {
+ return data2;
+ }
+
+ public void setData2(String data2) {
+ this.data2 = data2;
+ }
+
+ public int getNumData() {
+ return numData;
+ }
+
+ public void setNumData(int numData) {
+ this.numData = numData;
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (data1 != null && !data1.isEmpty()) {
+ builder.append(data1);
+ builder.append(" (");
+
+ if (data2 != null && !data2.isEmpty()) {
+ if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+ builder.append(", ");
+ }
+ builder.append("data2: ");
+ builder.append(data2);
+ }
+
+ if (0 < numData) {
+ if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+ builder.append(", ");
+ }
+ builder.append("numData: ");
+ builder.append(numData);
+ }
+
+ builder.append(")");
+ }
+ return builder.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ TestAutoSerializerObject1 test = (TestAutoSerializerObject1) o;
+ // field comparison
+ return Objects.equals(data1, test.data1)
+ && Objects.equals(data2, test.data2) && Objects.equals(numData, test.numData);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + data1.hashCode();
+ result = 31 * result + data2.hashCode();
+ result = 31 * result + numData;
+ return result;
+ }
+
+}
diff --git a/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerObject2.java b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerObject2.java
new file mode 100644
index 0000000..ad03b96
--- /dev/null
+++ b/geode-cq/src/distributedTest/java/org/apache/geode/internal/cache/tier/sockets/TestAutoSerializerObject2.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.cache.tier.sockets;
+
+import java.util.Objects;
+
+import org.apache.geode.internal.PdxSerializerObject;
+
+/**
+ * <strong>Explicitly</strong> not serializable by java.io.Serializable,
+ * org.apache.geode.DataSerializable, or org.apache.geode.pdx.PdxSerializable.
+ */
+public class TestAutoSerializerObject2 implements PdxSerializerObject {
+ protected String data1;
+ protected String data2;
+ protected int numData;
+
+ public TestAutoSerializerObject2() {
+ this("", "", 0);
+ }
+
+ protected TestAutoSerializerObject2(String data1, String data2, int numData) {
+ this.data1 = data1;
+ this.data2 = data2;
+ this.numData = numData;
+ }
+
+ public String getData1() {
+ return data1;
+ }
+
+ public String getData2() {
+ return data2;
+ }
+
+ public void setData2(String data2) {
+ this.data2 = data2;
+ }
+
+ public int getNumData() {
+ return numData;
+ }
+
+ public void setNumData(int numData) {
+ this.numData = numData;
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (data1 != null && !data1.isEmpty()) {
+ builder.append(data1);
+ builder.append(" (");
+
+ if (data2 != null && !data2.isEmpty()) {
+ if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+ builder.append(", ");
+ }
+ builder.append("data2: ");
+ builder.append(data2);
+ }
+
+ if (0 < numData) {
+ if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+ builder.append(", ");
+ }
+ builder.append("numData: ");
+ builder.append(numData);
+ }
+
+ builder.append(")");
+ }
+ return builder.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ TestAutoSerializerObject2 test = (TestAutoSerializerObject2) o;
+ // field comparison
+ return Objects.equals(data1, test.data1)
+ && Objects.equals(data2, test.data2) && Objects.equals(numData, test.numData);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + data1.hashCode();
+ result = 31 * result + data2.hashCode();
+ result = 31 * result + numData;
+ return result;
+ }
+}