--- /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.sal.binding.test.bugfix;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.collect.ImmutableList;
+
+public class WriteParentReadChildTest extends AbstractDataServiceTest {
+
+ private static final String FLOW_ID = "1234";
+ private static final short TABLE_ID = (short) 0;
+ private static final String NODE_ID = "node:1";
+
+ private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+ private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID));
+ private static final TableKey TABLE_KEY = new TableKey(TABLE_ID);
+
+ private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+ .child(Node.class, NODE_KEY).toInstance();
+
+ private static final InstanceIdentifier<Table> TABLE_INSTANCE_ID_BA = //
+ InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) //
+ .augmentation(FlowCapableNode.class).child(Table.class, TABLE_KEY).build();
+
+ private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
+ InstanceIdentifier.builder(TABLE_INSTANCE_ID_BA) //
+ .child(Flow.class, FLOW_KEY) //
+ .toInstance();
+ /**
+ *
+ * The scenario tests writing parent node, which also contains child items
+ * and then reading child directly, by specifying path to the child.
+ *
+ * Expected behaviour is child is returned.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void writeTableReadFlow() throws Exception {
+
+ DataModificationTransaction modification = baDataService.beginTransaction();
+
+ Flow flow = new FlowBuilder() //
+ .setKey(FLOW_KEY) //
+ .setMatch(new MatchBuilder() //
+ .setVlanMatch(new VlanMatchBuilder() //
+ .setVlanId(new VlanIdBuilder() //
+ .setVlanId(new VlanId(10)) //
+ .build()) //
+ .build()) //
+ .build()) //
+ .setInstructions(new InstructionsBuilder() //
+ .setInstruction(ImmutableList.<Instruction>builder() //
+ .build()) //
+ .build()) //
+ .build();
+
+ Table table = new TableBuilder()
+ .setKey(TABLE_KEY)
+ .setFlow(ImmutableList.of(flow))
+ .build();
+
+ modification.putConfigurationData(TABLE_INSTANCE_ID_BA, table);
+ RpcResult<TransactionStatus> ret = modification.commit().get();
+ assertNotNull(ret);
+ assertEquals(TransactionStatus.COMMITED, ret.getResult());
+
+ DataObject readedTable = baDataService.readConfigurationData(TABLE_INSTANCE_ID_BA);
+ assertNotNull("Readed table should not be nul.", readedTable);
+ assertTrue(readedTable instanceof Table);
+
+ DataObject readedFlow = baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA);
+ assertNotNull("Readed flow should not be null.",readedFlow);
+ assertTrue(readedFlow instanceof Flow);
+ assertEquals(flow, readedFlow);
+
+ }
+}
\ No newline at end of file
import static com.google.common.base.Preconditions.checkState;
+import java.io.Console;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.concurrent.Future;
+import javax.activation.UnsupportedDataTypeException;
+
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder;
import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
DataModification<InstanceIdentifier, CompositeNode> original) {
NormalizedDataModification normalized = new NormalizedDataModification(original);
for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
- normalized.putConfigurationData(entry.getKey(), entry.getValue());
+ normalized.putDeepConfigurationData(entry.getKey(), entry.getValue());
}
for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
- normalized.putOperationalData(entry.getKey(), entry.getValue());
+ normalized.putDeepOperationalData(entry.getKey(), entry.getValue());
}
for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
normalized.deepRemoveConfigurationData(entry);
private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
+ private final String CONFIGURATIONAL_DATA_STORE_MARKER = "configurational";
+ private final String OPERATIONAL_DATA_STORE_MARKER = "operational";
private final Object identifier;
private TransactionStatus status;
}
}
+ public void putDeepConfigurationData(InstanceIdentifier entryKey, CompositeNode entryData) {
+ this.putCompositeNodeData(entryKey, entryData, CONFIGURATIONAL_DATA_STORE_MARKER);
+ }
+
+ public void putDeepOperationalData(InstanceIdentifier entryKey, CompositeNode entryData) {
+ this.putCompositeNodeData(entryKey, entryData, OPERATIONAL_DATA_STORE_MARKER);
+ }
+
@Override
public Object getIdentifier() {
return this.identifier;
CompositeNode modified) {
return mergeData(path, stored, modified, false);
}
- }
+ private void putData(InstanceIdentifier entryKey, CompositeNode entryData, String dataStoreIdentifier) {
+ if (dataStoreIdentifier != null && entryKey != null && entryData != null) {
+ switch (dataStoreIdentifier) {
+ case (CONFIGURATIONAL_DATA_STORE_MARKER):
+ this.putConfigurationData(entryKey, entryData);
+ break;
+ case (OPERATIONAL_DATA_STORE_MARKER):
+ this.putOperationalData(entryKey, entryData);
+ break;
+
+ default :
+ LOG.error(dataStoreIdentifier + " is NOT valid DataStore switch marker");
+ throw new RuntimeException(dataStoreIdentifier + " is NOT valid DataStore switch marker");
+ }
+ }
+ }
+
+ private void putCompositeNodeData(InstanceIdentifier entryKey, CompositeNode entryData, String dataStoreIdentifier) {
+ this.putData(entryKey, entryData, dataStoreIdentifier);
+
+ for (Node<?> child : entryData.getChildren()) {
+ InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType()).toInstance();
+ if (child instanceof CompositeNode) {
+ DataSchemaNode subSchema = schemaNodeFor(subEntryId);
+ CompositeNode compNode = (CompositeNode) child;
+ InstanceIdentifier instanceId = null;
+
+ if (subSchema instanceof ListSchemaNode) {
+ ListSchemaNode listSubSchema = (ListSchemaNode) subSchema;
+ Map<QName, Object> mapOfSubValues = this.getValuesFromListSchema(listSubSchema, (CompositeNode) child);
+ if (mapOfSubValues != null) {
+ instanceId = InstanceIdentifier.builder(entryKey).nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance();
+ }
+ }
+ else if (subSchema instanceof ContainerSchemaNode) {
+ ContainerSchemaNode containerSchema = (ContainerSchemaNode) subSchema;
+ instanceId = InstanceIdentifier.builder(entryKey).node(subSchema.getQName()).toInstance();
+ }
+ if (instanceId != null) {
+ this.putCompositeNodeData(instanceId, compNode, dataStoreIdentifier);
+ }
+ }
+ }
+ }
+
+ private Map<QName, Object> getValuesFromListSchema (ListSchemaNode listSchema, CompositeNode entryData) {
+ List<QName> keyDef = listSchema.getKeyDefinition();
+ if (keyDef != null && ! keyDef.isEmpty()) {
+ Map<QName, Object> map = new HashMap<QName, Object>();
+ for (QName key : keyDef) {
+ List<Node<?>> data = entryData.get(key);
+ if (data != null && ! data.isEmpty()) {
+ for (Node<?> nodeData : data) {
+ if (nodeData instanceof SimpleNode<?>) {
+ map.put(key, data.get(0).getValue());
+ }
+ }
+ }
+ }
+ return map;
+ }
+ return null;
+ }
+ }
}