--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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;
+
+import akka.actor.ActorRef;
+
+public interface ClusterWrapper {
+ void subscribeToMemberEvents(ActorRef actorRef);
+ String getCurrentMemberName();
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.cluster.Cluster;
+import akka.cluster.ClusterEvent;
+
+public class ClusterWrapperImpl implements ClusterWrapper {
+ private final Cluster cluster;
+ private final String currentMemberName;
+
+ public ClusterWrapperImpl(ActorSystem actorSystem){
+ cluster = Cluster.get(actorSystem);
+ currentMemberName = (String) cluster.getSelfRoles().toArray()[0];
+
+ }
+
+ public void subscribeToMemberEvents(ActorRef actorRef){
+ cluster.subscribe(actorRef, ClusterEvent.initialStateAsEvents(),
+ ClusterEvent.MemberEvent.class,
+ ClusterEvent.UnreachableMember.class);
+ }
+
+ public String getCurrentMemberName() {
+ return currentMemberName;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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;
+
+import java.util.List;
+
+public interface Configuration {
+ List<String> getMemberShardNames(String memberName);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConfigurationImpl implements Configuration {
+ private final List<ModuleShard> moduleShards = new ArrayList<>();
+ private final List<Module> modules = new ArrayList<>();
+
+
+ public ConfigurationImpl(String moduleShardsConfigPath,
+ String modulesConfigPath){
+ Config moduleShardsConfig = ConfigFactory.load(moduleShardsConfigPath);
+ Config modulesConfig = ConfigFactory.load(modulesConfigPath);
+
+ readModuleShards(moduleShardsConfig);
+
+ readModules(modulesConfig);
+ }
+
+ public List<String> getMemberShardNames(String memberName){
+
+ List<String> shards = new ArrayList();
+ for(ModuleShard ms : moduleShards){
+ for(Shard s : ms.getShards()){
+ for(String m : s.getReplicas()){
+ if(memberName.equals(m)){
+ shards.add(s.getName());
+ }
+ }
+ }
+ }
+ return shards;
+
+ }
+
+
+ private void readModules(Config modulesConfig) {
+ List<? extends ConfigObject> modulesConfigObjectList =
+ modulesConfig.getObjectList("modules");
+
+ for(ConfigObject o : modulesConfigObjectList){
+ ConfigObjectWrapper w = new ConfigObjectWrapper(o);
+ modules.add(new Module(w.stringValue("name"), w.stringValue(
+ "namespace"), w.stringValue("sharding-strategy")));
+ }
+ }
+
+ private void readModuleShards(Config moduleShardsConfig) {
+ List<? extends ConfigObject> moduleShardsConfigObjectList =
+ moduleShardsConfig.getObjectList("module-shards");
+
+ for(ConfigObject moduleShardConfigObject : moduleShardsConfigObjectList){
+
+ String moduleName = moduleShardConfigObject.get("name").unwrapped().toString();
+
+ List<? extends ConfigObject> shardsConfigObjectList =
+ moduleShardConfigObject.toConfig().getObjectList("shards");
+
+ List<Shard> shards = new ArrayList<>();
+
+ for(ConfigObject shard : shardsConfigObjectList){
+ String shardName = shard.get("name").unwrapped().toString();
+ List<String> replicas = shard.toConfig().getStringList("replicas");
+ shards.add(new Shard(shardName, replicas));
+ }
+
+ this.moduleShards.add(new ModuleShard(moduleName, shards));
+ }
+ }
+
+
+ public static class ModuleShard {
+ private final String moduleName;
+ private final List<Shard> shards;
+
+ public ModuleShard(String moduleName, List<Shard> shards) {
+ this.moduleName = moduleName;
+ this.shards = shards;
+ }
+
+ public String getModuleName() {
+ return moduleName;
+ }
+
+ public List<Shard> getShards() {
+ return shards;
+ }
+ }
+
+ public static class Shard {
+ private final String name;
+ private final List<String> replicas;
+
+ Shard(String name, List<String> replicas) {
+ this.name = name;
+ this.replicas = replicas;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List<String> getReplicas() {
+ return replicas;
+ }
+ }
+
+ public static class Module {
+
+ private final String name;
+ private final String nameSpace;
+ private final String shardingStrategy;
+
+ Module(String name, String nameSpace, String shardingStrategy) {
+ this.name = name;
+ this.nameSpace = nameSpace;
+ this.shardingStrategy = shardingStrategy;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getNameSpace() {
+ return nameSpace;
+ }
+
+ public String getShardingStrategy() {
+ return shardingStrategy;
+ }
+ }
+
+
+ private static class ConfigObjectWrapper{
+
+ private final ConfigObject configObject;
+
+ ConfigObjectWrapper(ConfigObject configObject){
+ this.configObject = configObject;
+ }
+
+ public String stringValue(String name){
+ return configObject.get(name).unwrapped().toString();
+ }
+ }
+}
private final ExecutorService executor =
Executors.newFixedThreadPool(10);
- public DistributedDataStore(ActorSystem actorSystem, String type) {
- this(new ActorContext(actorSystem, actorSystem.actorOf(ShardManager.props(type), "shardmanager-" + type)), type);
+ public DistributedDataStore(ActorSystem actorSystem, String type, ClusterWrapper cluster, Configuration configuration) {
+ this(new ActorContext(actorSystem, actorSystem.actorOf(ShardManager.props(type, cluster, configuration), "shardmanager-" + type), configuration), type);
}
public DistributedDataStore(ActorContext actorContext, String type) {
package org.opendaylight.controller.cluster.datastore;
+import akka.actor.ActorSystem;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
public class DistributedDataStoreFactory {
public static DistributedDataStore createInstance(String name, SchemaService schemaService){
+ ActorSystem actorSystem = ActorSystemFactory.getInstance();
final DistributedDataStore dataStore =
- new DistributedDataStore(ActorSystemFactory.getInstance(), name);
+ new DistributedDataStore(actorSystem, name, new ClusterWrapperImpl(actorSystem), new ConfigurationImpl("module-shards.conf", "modules.conf"));
schemaService
.registerSchemaServiceListener(dataStore);
return dataStore;
*/
public class ShardManager extends AbstractUntypedActor {
- // Stores a mapping between a shard name and the address of the current primary
- private final Map<String, Address> shardNameToPrimaryAddress = new HashMap<>();
-
- // Stores a mapping between a member name and the address of the member
- private final Map<String, Address> memberNameToAddress = new HashMap<>();
-
- // Stores a mapping between the shard name and all the members on which a replica of that shard are available
- private final Map<String, List<String>> shardNameToMembers = new HashMap<>();
-
- private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
-
- private final ActorPath defaultShardPath;
-
- /**
- *
- * @param type defines the kind of data that goes into shards created by this shard manager. Examples of type would be
- * configuration or operational
- */
- private ShardManager(String type){
- ActorRef actor = getContext().actorOf(Shard.props("shard-" + Shard.DEFAULT_NAME + "-" + type), "shard-" + Shard.DEFAULT_NAME + "-" + type);
- defaultShardPath = actor.path();
- }
-
- public static Props props(final String type){
- return Props.create(new Creator<ShardManager>(){
-
- @Override
- public ShardManager create() throws Exception {
- return new ShardManager(type);
- }
- });
- }
-
- @Override
- public void handleReceive(Object message) throws Exception {
- if (message instanceof FindPrimary) {
- FindPrimary msg = ((FindPrimary) message);
- String shardName = msg.getShardName();
- if(Shard.DEFAULT_NAME.equals(shardName)){
- getSender().tell(new PrimaryFound(defaultShardPath.toString()), getSelf());
- } else {
- getSender().tell(new PrimaryNotFound(shardName), getSelf());
- }
- } else if(message instanceof UpdateSchemaContext){
- // FIXME : Notify all local shards of a schemaContext change
- getContext().system().actorSelection(defaultShardPath).forward(message, getContext());
+ // Stores a mapping between a shard name and the address of the current primary
+ private final Map<String, Address> shardNameToPrimaryAddress =
+ new HashMap<>();
+
+ // Stores a mapping between a member name and the address of the member
+ private final Map<String, Address> memberNameToAddress = new HashMap<>();
+
+ // Stores a mapping between the shard name and all the members on which a replica of that shard are available
+ private final Map<String, List<String>> shardNameToMembers =
+ new HashMap<>();
+
+ private final LoggingAdapter log =
+ Logging.getLogger(getContext().system(), this);
+
+
+ private final Map<String, ActorPath> localShards = new HashMap<>();
+
+
+ private final ClusterWrapper cluster;
+
+ /**
+ * @param type defines the kind of data that goes into shards created by this shard manager. Examples of type would be
+ * configuration or operational
+ */
+ private ShardManager(String type, ClusterWrapper cluster, Configuration configuration) {
+ this.cluster = cluster;
+ String memberName = cluster.getCurrentMemberName();
+ List<String> memberShardNames =
+ configuration.getMemberShardNames(memberName);
+
+ for(String shardName : memberShardNames){
+ ActorRef actor = getContext()
+ .actorOf(Shard.props(memberName + "-shard-" + shardName + "-" + type),
+ memberName + "-shard-" + shardName + "-" + type);
+ ActorPath path = actor.path();
+ localShards.put(shardName, path);
+ }
+ }
+
+ public static Props props(final String type,
+ final ClusterWrapper cluster,
+ final Configuration configuration) {
+ return Props.create(new Creator<ShardManager>() {
+
+ @Override
+ public ShardManager create() throws Exception {
+ return new ShardManager(type, cluster, configuration);
+ }
+ });
+ }
+
+ @Override
+ public void handleReceive(Object message) throws Exception {
+ if (message instanceof FindPrimary) {
+ FindPrimary msg = ((FindPrimary) message);
+ String shardName = msg.getShardName();
+
+
+ if (Shard.DEFAULT_NAME.equals(shardName)) {
+ ActorPath defaultShardPath = localShards.get(shardName);
+ if(defaultShardPath == null){
+ throw new IllegalStateException("local default shard not found");
+ }
+ getSender().tell(new PrimaryFound(defaultShardPath.toString()),
+ getSelf());
+ } else {
+ getSender().tell(new PrimaryNotFound(shardName), getSelf());
+ }
+ } else if (message instanceof UpdateSchemaContext) {
+ for(ActorPath path : localShards.values()){
+ getContext().system().actorSelection(path)
+ .forward(message,
+ getContext());
+ }
+ }
}
- }
}
import akka.actor.ActorSystem;
import akka.actor.PoisonPill;
import akka.util.Timeout;
+import org.opendaylight.controller.cluster.datastore.Configuration;
import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException;
import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException;
import org.opendaylight.controller.cluster.datastore.messages.FindPrimary;
private final ActorSystem actorSystem;
private final ActorRef shardManager;
+ private final Configuration configuration;
private SchemaContext schemaContext = null;
- public ActorContext(ActorSystem actorSystem, ActorRef shardManager){
+ public ActorContext(ActorSystem actorSystem, ActorRef shardManager, Configuration configuration){
this.actorSystem = actorSystem;
this.shardManager = shardManager;
+ this.configuration = configuration;
}
public ActorSystem getActorSystem() {
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import junit.framework.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+
+public class ConfigurationImplTest {
+
+ private static ConfigurationImpl configuration;
+
+ @BeforeClass
+ public static void staticSetup(){
+ configuration = new ConfigurationImpl("module-shards.conf", "modules.conf");
+ }
+
+ @Test
+ public void testConstructor(){
+ Assert.assertNotNull(configuration);
+ }
+
+ @Test
+ public void testGetMemberShardNames(){
+ List<String> memberShardNames =
+ configuration.getMemberShardNames("member-1");
+
+ assertTrue(memberShardNames.contains("people-1"));
+ assertTrue(memberShardNames.contains("cars-1"));
+ }
+}
import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor;
import org.opendaylight.controller.cluster.datastore.utils.MessageCollectorActor;
+import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
//Check if it was received by the remote actor
ActorContext
- testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)));
+ testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)), new MockConfiguration());
Object messages = testContext
.executeLocalOperation(actorRef, "messages",
ActorContext.ASK_DURATION);
import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor;
import org.opendaylight.controller.cluster.datastore.utils.MessageCollectorActor;
+import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
//Check if it was received by the remote actor
ActorContext
- testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)));
+ testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)), new MockConfiguration());
Object messages = testContext
.executeLocalOperation(actorRef, "messages",
ActorContext.ASK_DURATION);
import com.google.common.base.Optional;
import com.google.common.util.concurrent.ListenableFuture;
import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper;
+import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration;
import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
@Test
public void integrationTest() throws Exception {
DistributedDataStore distributedDataStore =
- new DistributedDataStore(getSystem(), "config");
+ new DistributedDataStore(getSystem(), "config", new MockClusterWrapper(), new MockConfiguration());
distributedDataStore.onGlobalContextUpdated(TestModel.createTestContext());
import org.opendaylight.controller.cluster.datastore.messages.FindPrimary;
import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound;
import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound;
+import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper;
+import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration;
import scala.concurrent.duration.Duration;
public class ShardManagerTest {
public void testOnReceiveFindPrimaryForNonExistentShard() throws Exception {
new JavaTestKit(system) {{
- final Props props = ShardManager.props("config");
+ final Props props = ShardManager.props("config", new MockClusterWrapper(), new MockConfiguration());
final TestActorRef<ShardManager> subject = TestActorRef.create(system, props);
new Within(duration("1 seconds")) {
public void testOnReceiveFindPrimaryForExistentShard() throws Exception {
new JavaTestKit(system) {{
- final Props props = ShardManager.props("config");
+ final Props props = ShardManager.props("config", new MockClusterWrapper(), new MockConfiguration());
final TestActorRef<ShardManager> subject = TestActorRef.create(system, props);
// the run() method needs to finish within 3 seconds
};
}};
}
-}
\ No newline at end of file
+}
import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChain;
import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChainReply;
+import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages.CreateTransactionReply;
import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply;
protected void run() {
subject.tell(
- new UpdateSchemaContext(TestModel.createTestContext()),
+ new UpdateSchemaContext(SchemaContextHelper.full()),
getRef());
subject.tell(new RegisterChangeListener(TestModel.TEST_PATH,
import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor;
import org.opendaylight.controller.cluster.datastore.utils.MessageCollectorActor;
import org.opendaylight.controller.cluster.datastore.utils.MockActorContext;
+import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration;
import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages.CreateTransactionReply;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
public class TransactionProxyTest extends AbstractActorTest {
+ private final ActorContext testContext =
+ new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)), new MockConfiguration());
+
private ExecutorService transactionExecutor =
Executors.newSingleThreadExecutor();
transactionProxy.write(TestModel.TEST_PATH,
ImmutableNodes.containerNode(TestModel.NAME_QNAME));
- ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)));
Object messages = testContext
.executeLocalOperation(actorRef, "messages",
ActorContext.ASK_DURATION);
transactionProxy.merge(TestModel.TEST_PATH,
ImmutableNodes.containerNode(TestModel.NAME_QNAME));
- ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)));
Object messages = testContext
.executeLocalOperation(actorRef, "messages",
ActorContext.ASK_DURATION);
transactionProxy.delete(TestModel.TEST_PATH);
- ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)));
Object messages = testContext
.executeLocalOperation(actorRef, "messages",
ActorContext.ASK_DURATION);
transactionProxy.close();
- ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)));
Object messages = testContext
.executeLocalOperation(actorRef, "messages",
ActorContext.ASK_DURATION);
private Object executeLocalOperationResponse;
public MockActorContext(ActorSystem actorSystem) {
- super(actorSystem, null);
+ super(actorSystem, null, new MockConfiguration());
}
public MockActorContext(ActorSystem actorSystem, ActorRef shardManager) {
- super(actorSystem, shardManager);
+ super(actorSystem, shardManager, new MockConfiguration());
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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.utils;
+
+import akka.actor.ActorRef;
+import org.opendaylight.controller.cluster.datastore.ClusterWrapper;
+
+public class MockClusterWrapper implements ClusterWrapper{
+
+ @Override public void subscribeToMemberEvents(ActorRef actorRef) {
+ throw new UnsupportedOperationException("subscribeToMemberEvents");
+ }
+
+ @Override public String getCurrentMemberName() {
+ return "member-1";
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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.utils;
+
+import org.opendaylight.controller.cluster.datastore.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MockConfiguration implements Configuration{
+ @Override public List<String> getMemberShardNames(String memberName) {
+ List<String> shardNames = new ArrayList<>();
+ shardNames.add("default");
+ return shardNames;
+ }
+}
public static void assertFirstSentMessage(ActorSystem actorSystem, ActorRef actorRef, Class clazz){
ActorContext testContext = new ActorContext(actorSystem, actorSystem.actorOf(
- Props.create(DoNothingActor.class)));
+ Props.create(DoNothingActor.class)), new MockConfiguration());
Object messages = testContext
.executeLocalOperation(actorRef, "messages",
ActorContext.ASK_DURATION);
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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.md.cluster.datastore.model;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+
+public class CarsModel {
+ public static final QName BASE_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:cars", "2014-03-13",
+ "cars");
+
+ public static final QName CARS_QNAME = QName.create(BASE_QNAME, "cars");
+ public static final QName CAR_QNAME = QName.create(CARS_QNAME, "car");
+ public static final QName CAR_NAME_QNAME = QName.create(CAR_QNAME, "name");
+ public static final QName CAR_PRICE_QNAME = QName.create(CAR_QNAME, "price");
+
+
+ public static NormalizedNode create(){
+
+ // Create a list builder
+ CollectionNodeBuilder<MapEntryNode, MapNode> cars =
+ ImmutableMapNodeBuilder.create().withNodeIdentifier(
+ new InstanceIdentifier.NodeIdentifier(
+ QName.create(CARS_QNAME, "car")));
+
+ // Create an entry for the car altima
+ MapEntryNode altima =
+ ImmutableNodes.mapEntryBuilder(CARS_QNAME, CAR_NAME_QNAME, "altima")
+ .withChild(ImmutableNodes.leafNode(CAR_NAME_QNAME, "altima"))
+ .withChild(ImmutableNodes.leafNode(CAR_PRICE_QNAME, 1000))
+ .build();
+
+ // Create an entry for the car accord
+ MapEntryNode honda =
+ ImmutableNodes.mapEntryBuilder(CARS_QNAME, CAR_NAME_QNAME, "accord")
+ .withChild(ImmutableNodes.leafNode(CAR_NAME_QNAME, "accord"))
+ .withChild(ImmutableNodes.leafNode(CAR_PRICE_QNAME, 2000))
+ .build();
+
+ cars.withChild(altima);
+ cars.withChild(honda);
+
+ return ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(BASE_QNAME))
+ .withChild(cars.build())
+ .build();
+
+ }
+
+ public static NormalizedNode emptyContainer(){
+ return ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(BASE_QNAME))
+ .build();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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.md.cluster.datastore.model;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+
+public class PeopleModel {
+ public static final QName BASE_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:people", "2014-03-13",
+ "people");
+
+ public static final QName PEOPLE_QNAME = QName.create(BASE_QNAME, "people");
+ public static final QName PERSON_QNAME = QName.create(PEOPLE_QNAME, "person");
+ public static final QName PERSON_NAME_QNAME = QName.create(PERSON_QNAME, "name");
+ public static final QName PERSON_AGE_QNAME = QName.create(PERSON_QNAME, "age");
+
+
+ public static NormalizedNode create(){
+
+ // Create a list builder
+ CollectionNodeBuilder<MapEntryNode, MapNode> cars =
+ ImmutableMapNodeBuilder.create().withNodeIdentifier(
+ new InstanceIdentifier.NodeIdentifier(
+ QName.create(PEOPLE_QNAME, "person")));
+
+ // Create an entry for the person jack
+ MapEntryNode jack =
+ ImmutableNodes.mapEntryBuilder(PEOPLE_QNAME, PERSON_NAME_QNAME, "jack")
+ .withChild(ImmutableNodes.leafNode(PERSON_NAME_QNAME, "jack"))
+ .withChild(ImmutableNodes.leafNode(PERSON_AGE_QNAME, 100))
+ .build();
+
+ // Create an entry for the person jill
+ MapEntryNode jill =
+ ImmutableNodes.mapEntryBuilder(PEOPLE_QNAME, PERSON_NAME_QNAME, "jill")
+ .withChild(ImmutableNodes.leafNode(PERSON_NAME_QNAME, "jill"))
+ .withChild(ImmutableNodes.leafNode(PERSON_AGE_QNAME, 200))
+ .build();
+
+ cars.withChild(jack);
+ cars.withChild(jill);
+
+ return ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(BASE_QNAME))
+ .withChild(cars.build())
+ .build();
+
+ }
+
+ public static NormalizedNode emptyContainer(){
+ return ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(BASE_QNAME))
+ .build();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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.md.cluster.datastore.model;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec;
+import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class SampleModelsTest {
+ @Test
+ public void testPeopleModel(){
+ NormalizedNode<?, ?> expected = PeopleModel.emptyContainer();
+
+
+ NormalizedNodeMessages.Container node =
+ new NormalizedNodeToNodeCodec(SchemaContextHelper.full())
+ .encode(InstanceIdentifier.of(PeopleModel.BASE_QNAME),
+ expected);
+
+ NormalizedNodeMessages.Node normalizedNode =
+ node.getNormalizedNode();
+
+ NormalizedNode<?,?> actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode(InstanceIdentifier.of(PeopleModel.BASE_QNAME),
+ normalizedNode);
+
+
+ Assert.assertEquals(expected, actual);
+
+ }
+
+
+ @Test
+ public void testCarsModel(){
+ NormalizedNode<?, ?> expected = CarsModel.emptyContainer();
+
+
+ NormalizedNodeMessages.Container node =
+ new NormalizedNodeToNodeCodec(SchemaContextHelper.full())
+ .encode(InstanceIdentifier.of(CarsModel.BASE_QNAME),
+ expected);
+
+ NormalizedNodeMessages.Node normalizedNode =
+ node.getNormalizedNode();
+
+ NormalizedNode<?,?> actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode(InstanceIdentifier.of(CarsModel.BASE_QNAME),
+ normalizedNode);
+
+
+ Assert.assertEquals(expected, actual);
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco 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.md.cluster.datastore.model;
+
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class SchemaContextHelper {
+
+ public static InputStream getInputStream(final String yangFileName) {
+ return TestModel.class.getResourceAsStream(yangFileName);
+ }
+
+ public static SchemaContext full(){
+ YangParserImpl parser = new YangParserImpl();
+ List<InputStream> streams = new ArrayList<>();
+ streams.add(getInputStream("/odl-datastore-test.yang"));
+ streams.add(getInputStream("/people.yang"));
+ streams.add(getInputStream("/cars.yang"));
+
+ Set<Module> modules = parser.parseYangModelsFromStreams(streams);
+ return parser.resolveSchemaContext(modules);
+
+ }
+}
--- /dev/null
+module cars {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:cars";
+ prefix "cars";
+
+ revision "2014-03-13" {
+ description "Initial revision.";
+ }
+
+ container cars {
+ list car {
+ key name;
+ leaf name {
+ type string;
+ }
+
+ leaf price {
+ type uint64;
+ }
+ }
+ }
+}
--- /dev/null
+module-shards = [
+ {
+ name = "default"
+ shards = [
+ {
+ name="default",
+ replicas = [
+ "member-1",
+ "member-2",
+ "member-3"
+ ]
+ }
+ ]
+ },
+ {
+ name = "people"
+ shards = [
+ {
+ name="people-1"
+ replicas = [
+ "member-1",
+ "member-2",
+ "member-3"
+ ]
+ }
+ ]
+ },
+ {
+ name = "cars"
+ shards = [
+ {
+ name="cars-1"
+ replicas = [
+ "member-4",
+ "member-1",
+ "member-5"
+ ]
+ }
+ ]
+ }
+
+]
--- /dev/null
+modules = [
+ {
+ name = "people"
+ namespace = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:people"
+ sharding-strategy = "module"
+ },
+ {
+ name = "cars"
+ namespace = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:cars"
+ sharding-strategy = "module"
+ }
+
+]
--- /dev/null
+module people {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:people";
+ prefix "people";
+
+ revision "2014-03-13" {
+ description "Initial revision.";
+ }
+
+ container people {
+ list person {
+ key name;
+ leaf name {
+ type string;
+ }
+
+ leaf age {
+ type uint32;
+ }
+ }
+ }
+}