X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fdom%2Fbroker%2Fimpl%2FSchemaAwareDataStoreAdapter.java;h=1a572d157dba9f8272140495b8eabf9669df11bc;hb=aae09dbf11186d2cd30fe87692f746519b0958f9;hp=1f908140b0ba60ca286095e4c693804609ec3472;hpb=76925347a1925c00c8d479f455783565c0caaaa0;p=controller.git diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java index 1f908140b0..1a572d157d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java @@ -1,49 +1,62 @@ +/* + * 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.util.ArrayList; -import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.Future; +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.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.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; +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.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; - -import static com.google.common.base.Preconditions.*; +import com.google.common.collect.ImmutableSet; public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements // - DataStore, // - SchemaServiceListener, // - AutoCloseable { +DataStore, // +SchemaContextListener, // +AutoCloseable { private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class); private SchemaContext schema = null; private boolean validationEnabled = false; - private SchemaAwareDataMerger dataMerger = null; - private DataReader reader = new MergeFirstLevelReader(); + private final DataReader reader = new MergeFirstLevelReader(); @Override - public boolean containsConfigurationPath(InstanceIdentifier path) { + public boolean containsConfigurationPath(final InstanceIdentifier path) { try { getDelegateReadLock().lock(); return getDelegate().containsConfigurationPath(path); @@ -54,7 +67,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator requestCommit( - DataModification modification) { + final DataModification modification) { validateAgainstSchema(modification); - DataModification cleanedUp = prepareMergedTransaction(modification); + NormalizedDataModification cleanedUp = prepareMergedTransaction(modification); + cleanedUp.status = TransactionStatus.SUBMITED; return retrieveDelegate().requestCommit(cleanedUp); } @@ -108,28 +122,28 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator modification) { + private void validateAgainstSchema(final DataModification modification) { if (!validationEnabled) { return; } if (schema == null) { - LOG.info("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier()); + LOG.warn("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier()); return; } } @Override - protected void onDelegateChanged(DataStore oldDelegate, DataStore newDelegate) { + protected void onDelegateChanged(final DataStore oldDelegate, final DataStore newDelegate) { // NOOP } @Override - public void onGlobalContextUpdated(SchemaContext context) { + public void onGlobalContextUpdated(final SchemaContext context) { this.schema = context; } @@ -138,15 +152,77 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator prepareMergedTransaction( - DataModification original) { - // NOOP for now - return original; + protected CompositeNode mergeData(final InstanceIdentifier path, final CompositeNode stored, final CompositeNode modified, + final boolean config) { + // long startTime = System.nanoTime(); + try { + DataSchemaNode node = schemaNodeFor(path); + return YangDataOperations.merge(node, stored, modified, config); + } finally { + // System.out.println("Merge time: " + ((System.nanoTime() - + // startTime) / 1000.0d)); + } + } + + private DataSchemaNode schemaNodeFor(final InstanceIdentifier path) { + checkState(schema != null, "YANG Schema is not available"); + return YangSchemaUtils.getSchemaNode(schema, path); + } + + private NormalizedDataModification prepareMergedTransaction( + final DataModification original) { + NormalizedDataModification normalized = new NormalizedDataModification(original); + LOG.trace("Transaction: {} Removed Configuration {}, Removed Operational {}", original.getIdentifier(), + original.getRemovedConfigurationData(), original.getRemovedConfigurationData()); + LOG.trace("Transaction: {} Created Configuration {}, Created Operational {}", original.getIdentifier(), + original.getCreatedConfigurationData().entrySet(), original.getCreatedOperationalData().entrySet()); + LOG.trace("Transaction: {} Updated Configuration {}, Updated Operational {}", original.getIdentifier(), + original.getUpdatedConfigurationData().entrySet(), original.getUpdatedOperationalData().entrySet()); + + for (InstanceIdentifier entry : original.getRemovedConfigurationData()) { + normalized.deepRemoveConfigurationData(entry); + } + for (InstanceIdentifier entry : original.getRemovedOperationalData()) { + normalized.deepRemoveOperationalData(entry); + } + for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { + normalized.putDeepConfigurationData(entry.getKey(), entry.getValue()); + } + for (Entry entry : original.getUpdatedOperationalData().entrySet()) { + normalized.putDeepOperationalData(entry.getKey(), entry.getValue()); + } + return normalized; + } + + private Iterable getConfigurationSubpaths(final InstanceIdentifier entry) { + // FIXME: This should be replaced by index + Iterable paths = getStoredConfigurationPaths(); + + return getChildrenPaths(entry, paths); + + } + + public Iterable getOperationalSubpaths(final InstanceIdentifier entry) { + // FIXME: This should be indexed + Iterable paths = getStoredOperationalPaths(); + + return getChildrenPaths(entry, paths); + } + + private static final Iterable getChildrenPaths(final InstanceIdentifier entry, + final Iterable paths) { + ImmutableSet.Builder children = ImmutableSet.builder(); + for (InstanceIdentifier potential : paths) { + if (entry.contains(potential)) { + children.add(entry); + } + } + return children.build(); } private final Comparator> preparationComparator = new Comparator>() { @Override - public int compare(Entry o1, Entry o2) { + public int compare(final Entry o1, final Entry o2) { InstanceIdentifier o1Key = o1.getKey(); InstanceIdentifier o2Key = o2.getKey(); return Integer.compare(o1Key.getPath().size(), o2Key.getPath().size()); @@ -166,7 +242,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator> childNodes = new ArrayList>(); if (original != null) { - childNodes.addAll(original.getChildren()); + childNodes.addAll(original.getValue()); qname = original.getNodeType(); } else { qname = path.getPath().get(path.getPath().size() - 1).getNodeType(); @@ -175,7 +251,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator directChildren = FluentIterable.from(getStoredConfigurationPaths()) .filter(new Predicate() { @Override - public boolean apply(InstanceIdentifier input) { + public boolean apply(final InstanceIdentifier input) { if (path.contains(input)) { int nesting = input.getPath().size() - path.getPath().size(); if (nesting == 1) { @@ -209,7 +285,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator> childNodes = new ArrayList>(); if (original != null) { - childNodes.addAll(original.getChildren()); + childNodes.addAll(original.getValue()); qname = original.getNodeType(); } else { qname = path.getPath().get(path.getPath().size() - 1).getNodeType(); @@ -218,7 +294,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator directChildren = FluentIterable.from(getStoredOperationalPaths()) .filter(new Predicate() { @Override - public boolean apply(InstanceIdentifier input) { + public boolean apply(final InstanceIdentifier input) { if (path.contains(input)) { int nesting = input.getPath().size() - path.getPath().size(); if (nesting == 1) { @@ -242,4 +318,143 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator { + + 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(final DataModification original) { + super(getDelegate()); + identifier = original; + status = TransactionStatus.NEW; + } + + /** + * + * Ensures all subpaths are removed - this currently does slow lookup in + * all keys. + * + * @param entry + */ + public void deepRemoveOperationalData(final InstanceIdentifier entry) { + Iterable paths = getOperationalSubpaths(entry); + removeOperationalData(entry); + for (InstanceIdentifier potential : paths) { + removeOperationalData(potential); + } + } + + public void deepRemoveConfigurationData(final InstanceIdentifier entry) { + Iterable paths = getConfigurationSubpaths(entry); + removeConfigurationData(entry); + for (InstanceIdentifier potential : paths) { + removeConfigurationData(potential); + } + } + + public void putDeepConfigurationData(final InstanceIdentifier entryKey, final CompositeNode entryData) { + this.putCompositeNodeData(entryKey, entryData, CONFIGURATIONAL_DATA_STORE_MARKER); + } + + public void putDeepOperationalData(final InstanceIdentifier entryKey, final CompositeNode entryData) { + this.putCompositeNodeData(entryKey, entryData, OPERATIONAL_DATA_STORE_MARKER); + } + + @Override + public Object getIdentifier() { + return this.identifier; + } + + @Override + public TransactionStatus getStatus() { + return status; + } + + @Override + public Future> commit() { + throw new UnsupportedOperationException("Commit should not be invoked on this"); + } + + @Override + protected CompositeNode mergeConfigurationData(final InstanceIdentifier path, final CompositeNode stored, + final CompositeNode modified) { + return mergeData(path, stored, modified, true); + } + + @Override + protected CompositeNode mergeOperationalData(final InstanceIdentifier path, final CompositeNode stored, + final CompositeNode modified) { + return mergeData(path, stored, modified, false); + } + + private void putData(final InstanceIdentifier entryKey, final CompositeNode entryData, final 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(final InstanceIdentifier entryKey, final CompositeNode entryData, + final String dataStoreIdentifier) { + this.putData(entryKey, entryData, dataStoreIdentifier); + + for (Node child : entryData.getValue()) { + 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 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 getValuesFromListSchema(final ListSchemaNode listSchema, final CompositeNode entryData) { + List keyDef = listSchema.getKeyDefinition(); + if (keyDef != null && !keyDef.isEmpty()) { + Map map = new HashMap(); + for (QName key : keyDef) { + List> 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; + } + } }