1 package org.opendaylight.controller.sal.dom.broker.impl;
3 import java.util.ArrayList;
4 import java.util.Comparator;
5 import java.util.Map.Entry;
6 import java.util.concurrent.Future;
8 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
9 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
10 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
11 import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
12 import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
13 import org.opendaylight.controller.sal.core.api.data.DataStore;
14 import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils;
15 import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.common.RpcResult;
18 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
19 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.Node;
21 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
22 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
24 import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
28 import com.google.common.base.Predicate;
29 import com.google.common.collect.FluentIterable;
31 import static com.google.common.base.Preconditions.*;
33 public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
35 SchemaServiceListener, //
38 private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
40 private SchemaContext schema = null;
41 private boolean validationEnabled = false;
42 private DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
45 public boolean containsConfigurationPath(InstanceIdentifier path) {
47 getDelegateReadLock().lock();
48 return getDelegate().containsConfigurationPath(path);
51 getDelegateReadLock().unlock();
56 public boolean containsOperationalPath(InstanceIdentifier path) {
58 getDelegateReadLock().lock();
59 return getDelegate().containsOperationalPath(path);
62 getDelegateReadLock().unlock();
67 public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
69 getDelegateReadLock().lock();
70 return getDelegate().getStoredConfigurationPaths();
73 getDelegateReadLock().unlock();
78 public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
80 getDelegateReadLock().lock();
81 return getDelegate().getStoredOperationalPaths();
84 getDelegateReadLock().unlock();
89 public CompositeNode readConfigurationData(InstanceIdentifier path) {
90 return reader.readConfigurationData(path);
94 public CompositeNode readOperationalData(InstanceIdentifier path) {
95 return reader.readOperationalData(path);
99 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
100 DataModification<InstanceIdentifier, CompositeNode> modification) {
101 validateAgainstSchema(modification);
102 NormalizedDataModification cleanedUp = prepareMergedTransaction(modification);
103 cleanedUp.status = TransactionStatus.SUBMITED;
104 return retrieveDelegate().requestCommit(cleanedUp);
107 public boolean isValidationEnabled() {
108 return validationEnabled;
111 public void setValidationEnabled(boolean validationEnabled) {
112 this.validationEnabled = validationEnabled;
115 private void validateAgainstSchema(DataModification<InstanceIdentifier, CompositeNode> modification) {
116 if (!validationEnabled) {
120 if (schema == null) {
121 LOG.warn("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier());
127 protected void onDelegateChanged(DataStore oldDelegate, DataStore newDelegate) {
132 public void onGlobalContextUpdated(SchemaContext context) {
133 this.schema = context;
137 public void close() throws Exception {
141 protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
143 long startTime = System.nanoTime();
145 DataSchemaNode node = schemaNodeFor(path);
146 return YangDataOperations.merge(node, stored, modified, config);
148 // System.out.println("Merge time: " + ((System.nanoTime() -
149 // startTime) / 1000.0d));
153 private DataSchemaNode schemaNodeFor(InstanceIdentifier path) {
154 checkState(schema != null, "YANG Schema is not available");
155 return YangSchemaUtils.getSchemaNode(schema, path);
158 private NormalizedDataModification prepareMergedTransaction(
159 DataModification<InstanceIdentifier, CompositeNode> original) {
161 NormalizedDataModification normalized = new NormalizedDataModification(original);
162 for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
163 normalized.putConfigurationData(entry.getKey(), entry.getValue());
165 for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
166 normalized.putOperationalData(entry.getKey(), entry.getValue());
168 for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
169 normalized.removeConfigurationData(entry);
171 for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
172 normalized.removeOperationalData(entry);
177 private final Comparator<Entry<InstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<InstanceIdentifier, CompositeNode>>() {
179 public int compare(Entry<InstanceIdentifier, CompositeNode> o1, Entry<InstanceIdentifier, CompositeNode> o2) {
180 InstanceIdentifier o1Key = o1.getKey();
181 InstanceIdentifier o2Key = o2.getKey();
182 return Integer.compare(o1Key.getPath().size(), o2Key.getPath().size());
186 private class MergeFirstLevelReader implements DataReader<InstanceIdentifier, CompositeNode> {
189 public CompositeNode readConfigurationData(final InstanceIdentifier path) {
190 getDelegateReadLock().lock();
192 if (path.getPath().isEmpty()) {
196 CompositeNode original = getDelegate().readConfigurationData(path);
197 ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
198 if (original != null) {
199 childNodes.addAll(original.getChildren());
200 qname = original.getNodeType();
202 qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
205 FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredConfigurationPaths())
206 .filter(new Predicate<InstanceIdentifier>() {
208 public boolean apply(InstanceIdentifier input) {
209 if (path.contains(input)) {
210 int nesting = input.getPath().size() - path.getPath().size();
218 for (InstanceIdentifier instanceIdentifier : directChildren) {
219 childNodes.add(getDelegate().readConfigurationData(instanceIdentifier));
221 if (original == null && childNodes.isEmpty()) {
225 return new CompositeNodeTOImpl(qname, null, childNodes);
227 getDelegateReadLock().unlock();
232 public CompositeNode readOperationalData(final InstanceIdentifier path) {
233 getDelegateReadLock().lock();
235 if (path.getPath().isEmpty()) {
239 CompositeNode original = getDelegate().readOperationalData(path);
240 ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
241 if (original != null) {
242 childNodes.addAll(original.getChildren());
243 qname = original.getNodeType();
245 qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
248 FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredOperationalPaths())
249 .filter(new Predicate<InstanceIdentifier>() {
251 public boolean apply(InstanceIdentifier input) {
252 if (path.contains(input)) {
253 int nesting = input.getPath().size() - path.getPath().size();
262 for (InstanceIdentifier instanceIdentifier : directChildren) {
263 childNodes.add(getDelegate().readOperationalData(instanceIdentifier));
265 if (original == null && childNodes.isEmpty()) {
269 return new CompositeNodeTOImpl(qname, null, childNodes);
271 getDelegateReadLock().unlock();
276 private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
278 private Object identifier;
279 private TransactionStatus status;
281 public NormalizedDataModification(DataModification<InstanceIdentifier, CompositeNode> original) {
282 super(getDelegate());
283 identifier = original;
284 status = TransactionStatus.NEW;
288 public Object getIdentifier() {
289 return this.identifier;
293 public TransactionStatus getStatus() {
298 public Future<RpcResult<TransactionStatus>> commit() {
299 throw new UnsupportedOperationException("Commit should not be invoked on this");
303 protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored,
304 CompositeNode modified) {
305 return mergeData(path, stored, modified, true);
309 protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored,
310 CompositeNode modified) {
311 return mergeData(path, stored, modified, false);