Merge "Fixed for bug 1197"
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / ShardTransaction.java
index b316b9df04966d82faf19ffc0743994dc684ec4a..737f57bf5d7314536f5fc20b1cbc45167f1b6e97 100644 (file)
@@ -9,8 +9,8 @@
 package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorRef;
+import akka.actor.PoisonPill;
 import akka.actor.Props;
-import akka.actor.UntypedActor;
 import akka.event.Logging;
 import akka.event.LoggingAdapter;
 import akka.japi.Creator;
@@ -28,119 +28,207 @@ import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.WriteData;
 import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
+import org.opendaylight.controller.cluster.datastore.modification.CompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.DeleteModification;
+import org.opendaylight.controller.cluster.datastore.modification.ImmutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.MergeModification;
+import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 import java.util.concurrent.ExecutionException;
 
 /**
  * The ShardTransaction Actor represents a remote transaction
- *
+ * <p>
  * The ShardTransaction Actor delegates all actions to DOMDataReadWriteTransaction
- *
+ * </p>
+ * <p>
  * Even though the DOMStore and the DOMStoreTransactionChain implement multiple types of transactions
  * the ShardTransaction Actor only works with read-write transactions. This is just to keep the logic simple. At this
  * time there are no known advantages for creating a read-only or write-only transaction which may change over time
  * at which point we can optimize things in the distributed store as well.
- *
- * Handles Messages
- * ----------------
- * {@link org.opendaylight.controller.cluster.datastore.messages.ReadData}
- * {@link org.opendaylight.controller.cluster.datastore.messages.WriteData}
- * {@link org.opendaylight.controller.cluster.datastore.messages.MergeData}
- * {@link org.opendaylight.controller.cluster.datastore.messages.DeleteData}
- * {@link org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction}
- * {@link org.opendaylight.controller.cluster.datastore.messages.CloseTransaction}
+ * </p>
+ * <p>
+ * Handles Messages <br/>
+ * ---------------- <br/>
+ * <li> {@link org.opendaylight.controller.cluster.datastore.messages.ReadData}
+ * <li> {@link org.opendaylight.controller.cluster.datastore.messages.WriteData}
+ * <li> {@link org.opendaylight.controller.cluster.datastore.messages.MergeData}
+ * <li> {@link org.opendaylight.controller.cluster.datastore.messages.DeleteData}
+ * <li> {@link org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction}
+ * <li> {@link org.opendaylight.controller.cluster.datastore.messages.CloseTransaction}
+ * </p>
  */
-public class ShardTransaction extends UntypedActor {
-
-  private final DOMStoreReadWriteTransaction transaction;
-
-  private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
-
-  public ShardTransaction(DOMStoreReadWriteTransaction transaction) {
-    this.transaction = transaction;
-  }
-
-
-  public static Props props(final DOMStoreReadWriteTransaction transaction){
-    return Props.create(new Creator<ShardTransaction>(){
-
-      @Override
-      public ShardTransaction create() throws Exception {
-        return new ShardTransaction(transaction);
-      }
-    });
-  }
-
-  @Override
-  public void onReceive(Object message) throws Exception {
-    if(message instanceof ReadData){
-      readData((ReadData) message);
-    } else if(message instanceof WriteData){
-      writeData((WriteData) message);
-    } else if(message instanceof MergeData){
-      mergeData((MergeData) message);
-    } else if(message instanceof DeleteData){
-      deleteData((DeleteData) message);
-    } else if(message instanceof ReadyTransaction){
-      readyTransaction((ReadyTransaction) message);
-    } else if(message instanceof CloseTransaction){
-      closeTransaction((CloseTransaction) message);
+public class ShardTransaction extends AbstractUntypedActor {
+
+    private final ActorRef shardActor;
+    private final SchemaContext schemaContext;
+
+    // FIXME : see below
+    // If transactionChain is not null then this transaction is part of a
+    // transactionChain. Not really clear as to what that buys us
+    private final DOMStoreTransactionChain transactionChain;
+
+    private final DOMStoreReadWriteTransaction transaction;
+
+    private final MutableCompositeModification modification =
+        new MutableCompositeModification();
+
+    private final LoggingAdapter log =
+        Logging.getLogger(getContext().system(), this);
+
+    public ShardTransaction(DOMStoreReadWriteTransaction transaction,
+        ActorRef shardActor, SchemaContext schemaContext) {
+        this(null, transaction, shardActor, schemaContext);
+    }
+
+    public ShardTransaction(DOMStoreTransactionChain transactionChain, DOMStoreReadWriteTransaction transaction,
+        ActorRef shardActor, SchemaContext schemaContext) {
+        this.transactionChain = transactionChain;
+        this.transaction = transaction;
+        this.shardActor = shardActor;
+        this.schemaContext = schemaContext;
     }
-  }
-
-  private void readData(ReadData message) {
-    final ActorRef sender = getSender();
-    final ActorRef self = getSelf();
-    final InstanceIdentifier path = message.getPath();
-    final ListenableFuture<Optional<NormalizedNode<?, ?>>> future = transaction.read(path);
-
-    future.addListener(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          Optional<NormalizedNode<?, ?>> optional = future.get();
-          if(optional.isPresent()){
-            sender.tell(new ReadDataReply(optional.get()), self);
-          } else {
-            //TODO : Need to decide what to do here
-          }
-        } catch (InterruptedException | ExecutionException e) {
-          log.error(e, "An exception happened when reading data from path : " + path.toString());
+
+
+
+    public static Props props(final DOMStoreReadWriteTransaction transaction,
+        final ActorRef shardActor, final SchemaContext schemaContext) {
+        return Props.create(new Creator<ShardTransaction>() {
+
+            @Override
+            public ShardTransaction create() throws Exception {
+                return new ShardTransaction(transaction, shardActor, schemaContext);
+            }
+        });
+    }
+
+    public static Props props(final DOMStoreTransactionChain transactionChain, final DOMStoreReadWriteTransaction transaction,
+        final ActorRef shardActor, final SchemaContext schemaContext) {
+        return Props.create(new Creator<ShardTransaction>() {
+
+            @Override
+            public ShardTransaction create() throws Exception {
+                return new ShardTransaction(transactionChain, transaction, shardActor, schemaContext);
+            }
+        });
+    }
+
+
+    @Override
+    public void handleReceive(Object message) throws Exception {
+        if (ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            readData(ReadData.fromSerializable(message));
+        } else if (WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            writeData(WriteData.fromSerializable(message, schemaContext));
+        } else if (MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            mergeData(MergeData.fromSerializable(message, schemaContext));
+        } else if (DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            deleteData(DeleteData.fromSerizalizable(message));
+        } else if (ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            readyTransaction(new ReadyTransaction());
+        } else if (message.getClass().equals(CloseTransaction.SERIALIZABLE_CLASS)) {
+            closeTransaction(new CloseTransaction());
+        } else if (message instanceof GetCompositedModification) {
+            // This is here for testing only
+            getSender().tell(new GetCompositeModificationReply(
+                new ImmutableCompositeModification(modification)), getSelf());
+        }else{
+          throw new Exception ("Shard:handleRecieve received an unknown message"+message);
         }
+    }
 
-      }
-    }, getContext().dispatcher());
-  }
+    private void readData(ReadData message) {
+        final ActorRef sender = getSender();
+        final ActorRef self = getSelf();
+        final YangInstanceIdentifier path = message.getPath();
+        final ListenableFuture<Optional<NormalizedNode<?, ?>>> future =
+            transaction.read(path);
+
+        future.addListener(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Optional<NormalizedNode<?, ?>> optional = future.get();
+                    if (optional.isPresent()) {
+                        sender.tell(new ReadDataReply(schemaContext,optional.get()).toSerializable(), self);
+                    } else {
+                        sender.tell(new ReadDataReply(schemaContext,null).toSerializable(), self);
+                    }
+                } catch (InterruptedException | ExecutionException e) {
+                    log.error(e,
+                        "An exception happened when reading data from path : "
+                            + path.toString());
+                }
+
+            }
+        }, getContext().dispatcher());
+    }
+
+
+    private void writeData(WriteData message) {
+        modification.addModification(
+            new WriteModification(message.getPath(), message.getData(),schemaContext));
+        LOG.debug("writeData at path : " + message.getPath().toString());
+        transaction.write(message.getPath(), message.getData());
+        getSender().tell(new WriteDataReply().toSerializable(), getSelf());
+    }
 
+    private void mergeData(MergeData message) {
+        modification.addModification(
+            new MergeModification(message.getPath(), message.getData(), schemaContext));
+        LOG.debug("mergeData at path : " + message.getPath().toString());
+        transaction.merge(message.getPath(), message.getData());
+        getSender().tell(new MergeDataReply().toSerializable(), getSelf());
+    }
 
-  private void writeData(WriteData message){
-    transaction.write(message.getPath(), message.getData());
-    getSender().tell(new WriteDataReply(), getSelf());
-  }
+    private void deleteData(DeleteData message) {
+        modification.addModification(new DeleteModification(message.getPath()));
+        transaction.delete(message.getPath());
+        getSender().tell(new DeleteDataReply().toSerializable(), getSelf());
+    }
+
+    private void readyTransaction(ReadyTransaction message) {
+        DOMStoreThreePhaseCommitCohort cohort = transaction.ready();
+        ActorRef cohortActor = getContext().actorOf(
+            ThreePhaseCommitCohort.props(cohort, shardActor, modification), "cohort");
+        getSender()
+            .tell(new ReadyTransactionReply(cohortActor.path()).toSerializable(), getSelf());
+
+    }
+
+    private void closeTransaction(CloseTransaction message) {
+        transaction.close();
+        getSender().tell(new CloseTransactionReply().toSerializable(), getSelf());
+        getSelf().tell(PoisonPill.getInstance(), getSelf());
+    }
 
-  private void mergeData(MergeData message){
-    transaction.merge(message.getPath(), message.getData());
-    getSender().tell(new MergeDataReply(), getSelf());
-  }
 
-  private void deleteData(DeleteData message){
-    transaction.delete(message.getPath());
-    getSender().tell(new DeleteDataReply(), getSelf());
-  }
+    // These classes are in here for test purposes only
 
-  private void readyTransaction(ReadyTransaction message){
-    DOMStoreThreePhaseCommitCohort cohort = transaction.ready();
-    ActorRef cohortActor = getContext().actorOf(ThreePhaseCommitCohort.props(cohort));
-    getSender().tell(new ReadyTransactionReply(cohortActor.path()), getSelf());
 
-  }
+    static class GetCompositedModification {
 
-  private void closeTransaction(CloseTransaction message){
-    transaction.close();
-    getSender().tell(new CloseTransactionReply(), getSelf());
-  }
+    }
+
+
+    static class GetCompositeModificationReply {
+        private final CompositeModification modification;
+
+
+        GetCompositeModificationReply(CompositeModification modification) {
+            this.modification = modification;
+        }
+
+
+        public CompositeModification getModification() {
+            return modification;
+        }
+    }
 }