+/*
+ * 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.dom.broker.impl;
-import java.awt.PageAttributes.OriginType;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.io.Console;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
+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 java.util.concurrent.atomic.AtomicLong;
+
+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.impl.AbstractDataModification;
import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener;
+import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
+import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils;
import org.opendaylight.yangtools.yang.common.QName;
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.PathArgument;
+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.DataNodeContainer;
+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.Module;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.util.YangDataOperations;
-import org.opendaylight.yangtools.yang.util.YangSchemaUtils;
+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 static com.google.common.base.Preconditions.*;
-import org.opendaylight.yangtools.yang.util.YangDataOperations;
+import com.google.common.collect.ImmutableSet;
public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
DataStore, //
SchemaServiceListener, //
+ SchemaContextListener, //
AutoCloseable {
private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
private SchemaContext schema = null;
private boolean validationEnabled = false;
- private DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
+ private final DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
@Override
public boolean containsConfigurationPath(InstanceIdentifier path) {
protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
boolean config) {
- long startTime = System.nanoTime();
+ // long startTime = System.nanoTime();
try {
DataSchemaNode node = schemaNodeFor(path);
return YangDataOperations.merge(node, stored, modified, config);
private NormalizedDataModification prepareMergedTransaction(
DataModification<InstanceIdentifier, CompositeNode> original) {
- // NOOP for now
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.removeConfigurationData(entry);
+ normalized.deepRemoveConfigurationData(entry);
}
for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
- normalized.removeOperationalData(entry);
+ normalized.deepRemoveOperationalData(entry);
}
return normalized;
}
+ private Iterable<InstanceIdentifier> getConfigurationSubpaths(InstanceIdentifier entry) {
+ // FIXME: This should be replaced by index
+ Iterable<InstanceIdentifier> paths = getStoredConfigurationPaths();
+
+ return getChildrenPaths(entry, paths);
+
+ }
+
+ public Iterable<InstanceIdentifier> getOperationalSubpaths(InstanceIdentifier entry) {
+ // FIXME: This should be indexed
+ Iterable<InstanceIdentifier> paths = getStoredOperationalPaths();
+
+ return getChildrenPaths(entry, paths);
+ }
+
+ private static final Iterable<InstanceIdentifier> getChildrenPaths(InstanceIdentifier entry,
+ Iterable<InstanceIdentifier> paths) {
+ ImmutableSet.Builder<InstanceIdentifier> children = ImmutableSet.builder();
+ for (InstanceIdentifier potential : paths) {
+ if (entry.contains(potential)) {
+ children.add(entry);
+ }
+ }
+ return children.build();
+ }
+
private final Comparator<Entry<InstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<InstanceIdentifier, CompositeNode>>() {
@Override
public int compare(Entry<InstanceIdentifier, CompositeNode> o1, Entry<InstanceIdentifier, CompositeNode> o2) {
private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
- private Object identifier;
+ private final String CONFIGURATIONAL_DATA_STORE_MARKER = "configurational";
+ private final String OPERATIONAL_DATA_STORE_MARKER = "operational";
+ private final Object identifier;
private TransactionStatus status;
public NormalizedDataModification(DataModification<InstanceIdentifier, CompositeNode> original) {
status = TransactionStatus.NEW;
}
+ /**
+ *
+ * Ensures all subpaths are removed - this currently does slow lookup in
+ * all keys.
+ *
+ * @param entry
+ */
+ public void deepRemoveOperationalData(InstanceIdentifier entry) {
+ Iterable<InstanceIdentifier> paths = getOperationalSubpaths(entry);
+ removeOperationalData(entry);
+ for (InstanceIdentifier potential : paths) {
+ removeOperationalData(potential);
+ }
+ }
+
+ public void deepRemoveConfigurationData(InstanceIdentifier entry) {
+ Iterable<InstanceIdentifier> paths = getConfigurationSubpaths(entry);
+ removeConfigurationData(entry);
+ for (InstanceIdentifier potential : paths) {
+ removeConfigurationData(potential);
+ }
+ }
+
+ 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;
@Override
protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored,
CompositeNode modified) {
- // TODO Auto-generated method stub
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;
+ }
+ }
}