2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.sal.dom.broker.impl;
10 import java.util.ArrayList;
11 import java.util.Comparator;
12 import java.util.Map.Entry;
13 import java.util.concurrent.Future;
15 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
16 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
17 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
18 import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
19 import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
20 import org.opendaylight.controller.sal.core.api.data.DataStore;
21 import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils;
22 import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.common.RpcResult;
25 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
26 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.Node;
28 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
29 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
31 import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 import com.google.common.base.Predicate;
36 import com.google.common.collect.FluentIterable;
38 import static com.google.common.base.Preconditions.*;
40 public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
42 SchemaServiceListener, //
45 private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
47 private SchemaContext schema = null;
48 private boolean validationEnabled = false;
49 private DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
52 public boolean containsConfigurationPath(InstanceIdentifier path) {
54 getDelegateReadLock().lock();
55 return getDelegate().containsConfigurationPath(path);
58 getDelegateReadLock().unlock();
63 public boolean containsOperationalPath(InstanceIdentifier path) {
65 getDelegateReadLock().lock();
66 return getDelegate().containsOperationalPath(path);
69 getDelegateReadLock().unlock();
74 public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
76 getDelegateReadLock().lock();
77 return getDelegate().getStoredConfigurationPaths();
80 getDelegateReadLock().unlock();
85 public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
87 getDelegateReadLock().lock();
88 return getDelegate().getStoredOperationalPaths();
91 getDelegateReadLock().unlock();
96 public CompositeNode readConfigurationData(InstanceIdentifier path) {
97 return reader.readConfigurationData(path);
101 public CompositeNode readOperationalData(InstanceIdentifier path) {
102 return reader.readOperationalData(path);
106 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
107 DataModification<InstanceIdentifier, CompositeNode> modification) {
108 validateAgainstSchema(modification);
109 NormalizedDataModification cleanedUp = prepareMergedTransaction(modification);
110 cleanedUp.status = TransactionStatus.SUBMITED;
111 return retrieveDelegate().requestCommit(cleanedUp);
114 public boolean isValidationEnabled() {
115 return validationEnabled;
118 public void setValidationEnabled(boolean validationEnabled) {
119 this.validationEnabled = validationEnabled;
122 private void validateAgainstSchema(DataModification<InstanceIdentifier, CompositeNode> modification) {
123 if (!validationEnabled) {
127 if (schema == null) {
128 LOG.warn("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier());
134 protected void onDelegateChanged(DataStore oldDelegate, DataStore newDelegate) {
139 public void onGlobalContextUpdated(SchemaContext context) {
140 this.schema = context;
144 public void close() throws Exception {
148 protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
150 long startTime = System.nanoTime();
152 DataSchemaNode node = schemaNodeFor(path);
153 return YangDataOperations.merge(node, stored, modified, config);
155 // System.out.println("Merge time: " + ((System.nanoTime() -
156 // startTime) / 1000.0d));
160 private DataSchemaNode schemaNodeFor(InstanceIdentifier path) {
161 checkState(schema != null, "YANG Schema is not available");
162 return YangSchemaUtils.getSchemaNode(schema, path);
165 private NormalizedDataModification prepareMergedTransaction(
166 DataModification<InstanceIdentifier, CompositeNode> original) {
168 NormalizedDataModification normalized = new NormalizedDataModification(original);
169 for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
170 normalized.putConfigurationData(entry.getKey(), entry.getValue());
172 for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
173 normalized.putOperationalData(entry.getKey(), entry.getValue());
175 for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
176 normalized.removeConfigurationData(entry);
178 for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
179 normalized.removeOperationalData(entry);
184 private final Comparator<Entry<InstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<InstanceIdentifier, CompositeNode>>() {
186 public int compare(Entry<InstanceIdentifier, CompositeNode> o1, Entry<InstanceIdentifier, CompositeNode> o2) {
187 InstanceIdentifier o1Key = o1.getKey();
188 InstanceIdentifier o2Key = o2.getKey();
189 return Integer.compare(o1Key.getPath().size(), o2Key.getPath().size());
193 private class MergeFirstLevelReader implements DataReader<InstanceIdentifier, CompositeNode> {
196 public CompositeNode readConfigurationData(final InstanceIdentifier path) {
197 getDelegateReadLock().lock();
199 if (path.getPath().isEmpty()) {
203 CompositeNode original = getDelegate().readConfigurationData(path);
204 ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
205 if (original != null) {
206 childNodes.addAll(original.getChildren());
207 qname = original.getNodeType();
209 qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
212 FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredConfigurationPaths())
213 .filter(new Predicate<InstanceIdentifier>() {
215 public boolean apply(InstanceIdentifier input) {
216 if (path.contains(input)) {
217 int nesting = input.getPath().size() - path.getPath().size();
225 for (InstanceIdentifier instanceIdentifier : directChildren) {
226 childNodes.add(getDelegate().readConfigurationData(instanceIdentifier));
228 if (original == null && childNodes.isEmpty()) {
232 return new CompositeNodeTOImpl(qname, null, childNodes);
234 getDelegateReadLock().unlock();
239 public CompositeNode readOperationalData(final InstanceIdentifier path) {
240 getDelegateReadLock().lock();
242 if (path.getPath().isEmpty()) {
246 CompositeNode original = getDelegate().readOperationalData(path);
247 ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
248 if (original != null) {
249 childNodes.addAll(original.getChildren());
250 qname = original.getNodeType();
252 qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
255 FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredOperationalPaths())
256 .filter(new Predicate<InstanceIdentifier>() {
258 public boolean apply(InstanceIdentifier input) {
259 if (path.contains(input)) {
260 int nesting = input.getPath().size() - path.getPath().size();
269 for (InstanceIdentifier instanceIdentifier : directChildren) {
270 childNodes.add(getDelegate().readOperationalData(instanceIdentifier));
272 if (original == null && childNodes.isEmpty()) {
276 return new CompositeNodeTOImpl(qname, null, childNodes);
278 getDelegateReadLock().unlock();
283 private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
285 private Object identifier;
286 private TransactionStatus status;
288 public NormalizedDataModification(DataModification<InstanceIdentifier, CompositeNode> original) {
289 super(getDelegate());
290 identifier = original;
291 status = TransactionStatus.NEW;
295 public Object getIdentifier() {
296 return this.identifier;
300 public TransactionStatus getStatus() {
305 public Future<RpcResult<TransactionStatus>> commit() {
306 throw new UnsupportedOperationException("Commit should not be invoked on this");
310 protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored,
311 CompositeNode modified) {
312 return mergeData(path, stored, modified, true);
316 protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored,
317 CompositeNode modified) {
318 return mergeData(path, stored, modified, false);