} else if(MergeData.isSerializedType(message)) {
mergeData(transaction, MergeData.fromSerializable(message), SERIALIZED_REPLY);
- } else if(DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+ } else if(DeleteData.isSerializedType(message)) {
deleteData(transaction, DeleteData.fromSerializable(message), SERIALIZED_REPLY);
} else if(ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) {
modification.addModification(new DeleteModification(message.getPath()));
try {
transaction.delete(message.getPath());
- DeleteDataReply deleteDataReply = new DeleteDataReply();
- getSender().tell(returnSerialized ? deleteDataReply.toSerializable() : deleteDataReply,
- getSelf());
+ DeleteDataReply deleteDataReply = DeleteDataReply.INSTANCE;
+ getSender().tell(returnSerialized ? deleteDataReply.toSerializable(message.getVersion()) :
+ deleteDataReply, getSelf());
}catch(Exception e){
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
}
package org.opendaylight.controller.cluster.datastore.messages;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.opendaylight.controller.cluster.datastore.DataStoreVersions;
import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils;
+import org.opendaylight.controller.cluster.datastore.utils.SerializationUtils;
import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-public class DeleteData implements SerializableMessage {
+public class DeleteData implements VersionedSerializableMessage, Externalizable {
+ private static final long serialVersionUID = 1L;
- public static final Class<ShardTransactionMessages.DeleteData> SERIALIZABLE_CLASS = ShardTransactionMessages.DeleteData.class;
+ public static final Class<DeleteData> SERIALIZABLE_CLASS = DeleteData.class;
- private final YangInstanceIdentifier path;
+ private YangInstanceIdentifier path;
+ private short version;
+
+ public DeleteData() {
+ }
public DeleteData(final YangInstanceIdentifier path) {
this.path = path;
return path;
}
- @Override public Object toSerializable() {
- return ShardTransactionMessages.DeleteData.newBuilder()
- .setInstanceIdentifierPathArguments(InstanceIdentifierUtils.toSerializable(path)).build();
+ public short getVersion() {
+ return version;
+ }
+
+ @Override
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ version = in.readShort(); // Read the version - don't need to do anything with it now
+ path = SerializationUtils.deserializePath(in);
+ }
+
+ @Override
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeShort(version);
+ SerializationUtils.serializePath(path, out);
+ }
+
+ @Override
+ public Object toSerializable(short toVersion) {
+ if(toVersion >= DataStoreVersions.LITHIUM_VERSION) {
+ version = toVersion;
+ return this;
+ } else {
+ // To base or R1 Helium version
+ return ShardTransactionMessages.DeleteData.newBuilder().setInstanceIdentifierPathArguments(
+ InstanceIdentifierUtils.toSerializable(path)).build();
+ }
+ }
+
+ public static DeleteData fromSerializable(final Object serializable) {
+ if(serializable instanceof DeleteData) {
+ return (DeleteData) serializable;
+ } else {
+ // From base or R1 Helium version
+ ShardTransactionMessages.DeleteData o = (ShardTransactionMessages.DeleteData) serializable;
+ return new DeleteData(InstanceIdentifierUtils.fromSerializable(o.getInstanceIdentifierPathArguments()));
+ }
}
- public static DeleteData fromSerializable(final Object serializable){
- ShardTransactionMessages.DeleteData o = (ShardTransactionMessages.DeleteData) serializable;
- return new DeleteData(InstanceIdentifierUtils.fromSerializable(o.getInstanceIdentifierPathArguments()));
+ public static boolean isSerializedType(Object message) {
+ return SERIALIZABLE_CLASS.isInstance(message) ||
+ message instanceof ShardTransactionMessages.DeleteData;
}
}
import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
-public class DeleteDataReply implements SerializableMessage{
- public static final Class<ShardTransactionMessages.DeleteDataReply> SERIALIZABLE_CLASS =
- ShardTransactionMessages.DeleteDataReply.class;
+public class DeleteDataReply extends EmptyReply {
- private static final Object SERIALIZED_INSTANCE = ShardTransactionMessages.DeleteDataReply.newBuilder().build();
+ private static final Object LEGACY_SERIALIZED_INSTANCE =
+ ShardTransactionMessages.DeleteDataReply.newBuilder().build();
public static final DeleteDataReply INSTANCE = new DeleteDataReply();
- @Override
- public Object toSerializable() {
- return SERIALIZED_INSTANCE;
+ public DeleteDataReply() {
+ super(LEGACY_SERIALIZED_INSTANCE);
}
}
* @author Thomas Pantelis
*/
public final class SerializationUtils {
+
public static interface Applier<T> {
void apply(T instance, YangInstanceIdentifier path, NormalizedNode<?, ?> node);
}
return null;
}
+
+ public static void serializePath(YangInstanceIdentifier path, DataOutput out) {
+ Preconditions.checkNotNull(path);
+ try {
+ NormalizedNodeOutputStreamWriter streamWriter = new NormalizedNodeOutputStreamWriter(out);
+ streamWriter.writeYangInstanceIdentifier(path);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(String.format("Error serializing path {}", path), e);
+ }
+ }
+
+ public static YangInstanceIdentifier deserializePath(DataInput in) {
+ try {
+ NormalizedNodeInputStreamReader streamReader = new NormalizedNodeInputStreamReader(in);
+ return streamReader.readYangInstanceIdentifier();
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error deserializing path", e);
+ }
+ }
}
DataStoreVersions.CURRENT_VERSION);
final ActorRef transaction = getSystem().actorOf(props, "testDeleteData");
- transaction.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(), getRef());
+ transaction.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(
+ DataStoreVersions.HELIUM_2_VERSION), getRef());
expectMsgClass(duration("5 seconds"), ShardTransactionMessages.DeleteDataReply.class);
assertModification(transaction, DeleteModification.class);
- //unserialized merge
+ //unserialized
transaction.tell(new DeleteData(TestModel.TEST_PATH), getRef());
expectMsgClass(duration("5 seconds"), DeleteDataReply.class);
DataStoreVersions.CURRENT_VERSION);
final TestActorRef<ShardTransaction> transaction = TestActorRef.apply(props,getSystem());
- transaction.receive(new DeleteData(TestModel.TEST_PATH).toSerializable(), ActorRef.noSender());
+ transaction.receive(new DeleteData(TestModel.TEST_PATH).toSerializable(
+ DataStoreVersions.CURRENT_VERSION), ActorRef.noSender());
}
@Test
return Futures.successful(new MergeDataReply());
}
+ private Future<Object> deleteSerializedDataReply(short version) {
+ return Futures.successful(new DeleteDataReply().toSerializable(version));
+ }
+
private Future<Object> deleteSerializedDataReply() {
- return Futures.successful(new DeleteDataReply().toSerializable());
+ return deleteSerializedDataReply(DataStoreVersions.CURRENT_VERSION);
}
private Future<DeleteDataReply> deleteDataReply() {
eq(actorSelection(actorRef)), eqSerializedDeleteData());
verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
- DeleteDataReply.SERIALIZABLE_CLASS);
+ DeleteDataReply.class);
}
private void verifyCohortFutures(ThreePhaseCommitCohortProxy proxy,
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore.messages;
+
+import static org.junit.Assert.assertEquals;
+import java.io.Serializable;
+import org.apache.commons.lang.SerializationUtils;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.DataStoreVersions;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier;
+import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+/**
+ * Unit tests for DeleteData.
+ *
+ * @author Thomas Pantelis
+ */
+public class DeleteDataTest {
+
+ @Test
+ public void testSerialization() {
+ YangInstanceIdentifier path = TestModel.TEST_PATH;
+
+ DeleteData expected = new DeleteData(path);
+
+ Object serialized = expected.toSerializable(DataStoreVersions.CURRENT_VERSION);
+ assertEquals("Serialized type", DeleteData.class, serialized.getClass());
+ assertEquals("Version", DataStoreVersions.CURRENT_VERSION, ((DeleteData)serialized).getVersion());
+
+ Object clone = SerializationUtils.clone((Serializable) serialized);
+ assertEquals("Version", DataStoreVersions.CURRENT_VERSION, ((DeleteData)clone).getVersion());
+ DeleteData actual = DeleteData.fromSerializable(clone);
+ assertEquals("getPath", expected.getPath(), actual.getPath());
+ }
+
+ @Test
+ public void testIsSerializedType() {
+ assertEquals("isSerializedType", true, DeleteData.isSerializedType(
+ ShardTransactionMessages.DeleteData.newBuilder()
+ .setInstanceIdentifierPathArguments(InstanceIdentifier.getDefaultInstance()).build()));
+ assertEquals("isSerializedType", true,
+ DeleteData.isSerializedType(new DeleteData()));
+ assertEquals("isSerializedType", false, DeleteData.isSerializedType(new Object()));
+ }
+
+ /**
+ * Tests backwards compatible serialization/deserialization of a DeleteData message with the
+ * base and R1 Helium versions, which used the protobuff DeleteData message.
+ */
+ @Test
+ public void testSerializationWithHeliumR1Version() throws Exception {
+ YangInstanceIdentifier path = TestModel.TEST_PATH;
+
+ DeleteData expected = new DeleteData(path);
+
+ Object serialized = expected.toSerializable(DataStoreVersions.HELIUM_1_VERSION);
+ assertEquals("Serialized type", ShardTransactionMessages.DeleteData.class, serialized.getClass());
+
+ DeleteData actual = DeleteData.fromSerializable(SerializationUtils.clone((Serializable) serialized));
+ assertEquals("getPath", expected.getPath(), actual.getPath());
+ }
+}