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 static com.google.common.base.Preconditions.checkState;
12 import java.util.ArrayList;
13 import java.util.Comparator;
14 import java.util.Map.Entry;
15 import java.util.concurrent.Future;
17 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
18 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
19 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
20 import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
21 import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
22 import org.opendaylight.controller.sal.core.api.data.DataStore;
23 import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
24 import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.RpcResult;
27 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
28 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.Node;
30 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
31 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
34 import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import com.google.common.base.Predicate;
39 import com.google.common.collect.FluentIterable;
40 import com.google.common.collect.ImmutableSet;
42 public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
44 SchemaServiceListener, //
45 SchemaContextListener, //
48 private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
50 private SchemaContext schema = null;
51 private boolean validationEnabled = false;
52 private final DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
55 public boolean containsConfigurationPath(InstanceIdentifier path) {
57 getDelegateReadLock().lock();
58 return getDelegate().containsConfigurationPath(path);
61 getDelegateReadLock().unlock();
66 public boolean containsOperationalPath(InstanceIdentifier path) {
68 getDelegateReadLock().lock();
69 return getDelegate().containsOperationalPath(path);
72 getDelegateReadLock().unlock();
77 public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
79 getDelegateReadLock().lock();
80 return getDelegate().getStoredConfigurationPaths();
83 getDelegateReadLock().unlock();
88 public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
90 getDelegateReadLock().lock();
91 return getDelegate().getStoredOperationalPaths();
94 getDelegateReadLock().unlock();
99 public CompositeNode readConfigurationData(InstanceIdentifier path) {
100 return reader.readConfigurationData(path);
104 public CompositeNode readOperationalData(InstanceIdentifier path) {
105 return reader.readOperationalData(path);
109 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
110 DataModification<InstanceIdentifier, CompositeNode> modification) {
111 validateAgainstSchema(modification);
112 NormalizedDataModification cleanedUp = prepareMergedTransaction(modification);
113 cleanedUp.status = TransactionStatus.SUBMITED;
114 return retrieveDelegate().requestCommit(cleanedUp);
117 public boolean isValidationEnabled() {
118 return validationEnabled;
121 public void setValidationEnabled(boolean validationEnabled) {
122 this.validationEnabled = validationEnabled;
125 private void validateAgainstSchema(DataModification<InstanceIdentifier, CompositeNode> modification) {
126 if (!validationEnabled) {
130 if (schema == null) {
131 LOG.warn("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier());
137 protected void onDelegateChanged(DataStore oldDelegate, DataStore newDelegate) {
142 public void onGlobalContextUpdated(SchemaContext context) {
143 this.schema = context;
147 public void close() throws Exception {
151 protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
153 // long startTime = System.nanoTime();
155 DataSchemaNode node = schemaNodeFor(path);
156 return YangDataOperations.merge(node, stored, modified, config);
158 // System.out.println("Merge time: " + ((System.nanoTime() -
159 // startTime) / 1000.0d));
163 private DataSchemaNode schemaNodeFor(InstanceIdentifier path) {
164 checkState(schema != null, "YANG Schema is not available");
165 return YangSchemaUtils.getSchemaNode(schema, path);
168 private NormalizedDataModification prepareMergedTransaction(
169 DataModification<InstanceIdentifier, CompositeNode> original) {
170 NormalizedDataModification normalized = new NormalizedDataModification(original);
171 for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
172 normalized.putConfigurationData(entry.getKey(), entry.getValue());
174 for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
175 normalized.putOperationalData(entry.getKey(), entry.getValue());
177 for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
178 normalized.deepRemoveConfigurationData(entry);
180 for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
181 normalized.deepRemoveOperationalData(entry);
186 private Iterable<InstanceIdentifier> getConfigurationSubpaths(InstanceIdentifier entry) {
187 // FIXME: This should be replaced by index
188 Iterable<InstanceIdentifier> paths = getStoredConfigurationPaths();
190 return getChildrenPaths(entry, paths);
194 public Iterable<InstanceIdentifier> getOperationalSubpaths(InstanceIdentifier entry) {
195 // FIXME: This should be indexed
196 Iterable<InstanceIdentifier> paths = getStoredOperationalPaths();
198 return getChildrenPaths(entry, paths);
201 private static final Iterable<InstanceIdentifier> getChildrenPaths(InstanceIdentifier entry,
202 Iterable<InstanceIdentifier> paths) {
203 ImmutableSet.Builder<InstanceIdentifier> children = ImmutableSet.builder();
204 for (InstanceIdentifier potential : paths) {
205 if (entry.contains(potential)) {
209 return children.build();
212 private final Comparator<Entry<InstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<InstanceIdentifier, CompositeNode>>() {
214 public int compare(Entry<InstanceIdentifier, CompositeNode> o1, Entry<InstanceIdentifier, CompositeNode> o2) {
215 InstanceIdentifier o1Key = o1.getKey();
216 InstanceIdentifier o2Key = o2.getKey();
217 return Integer.compare(o1Key.getPath().size(), o2Key.getPath().size());
221 private class MergeFirstLevelReader implements DataReader<InstanceIdentifier, CompositeNode> {
224 public CompositeNode readConfigurationData(final InstanceIdentifier path) {
225 getDelegateReadLock().lock();
227 if (path.getPath().isEmpty()) {
231 CompositeNode original = getDelegate().readConfigurationData(path);
232 ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
233 if (original != null) {
234 childNodes.addAll(original.getChildren());
235 qname = original.getNodeType();
237 qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
240 FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredConfigurationPaths())
241 .filter(new Predicate<InstanceIdentifier>() {
243 public boolean apply(InstanceIdentifier input) {
244 if (path.contains(input)) {
245 int nesting = input.getPath().size() - path.getPath().size();
253 for (InstanceIdentifier instanceIdentifier : directChildren) {
254 childNodes.add(getDelegate().readConfigurationData(instanceIdentifier));
256 if (original == null && childNodes.isEmpty()) {
260 return new CompositeNodeTOImpl(qname, null, childNodes);
262 getDelegateReadLock().unlock();
267 public CompositeNode readOperationalData(final InstanceIdentifier path) {
268 getDelegateReadLock().lock();
270 if (path.getPath().isEmpty()) {
274 CompositeNode original = getDelegate().readOperationalData(path);
275 ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
276 if (original != null) {
277 childNodes.addAll(original.getChildren());
278 qname = original.getNodeType();
280 qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
283 FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredOperationalPaths())
284 .filter(new Predicate<InstanceIdentifier>() {
286 public boolean apply(InstanceIdentifier input) {
287 if (path.contains(input)) {
288 int nesting = input.getPath().size() - path.getPath().size();
297 for (InstanceIdentifier instanceIdentifier : directChildren) {
298 childNodes.add(getDelegate().readOperationalData(instanceIdentifier));
300 if (original == null && childNodes.isEmpty()) {
304 return new CompositeNodeTOImpl(qname, null, childNodes);
306 getDelegateReadLock().unlock();
311 private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
313 private final Object identifier;
314 private TransactionStatus status;
316 public NormalizedDataModification(DataModification<InstanceIdentifier, CompositeNode> original) {
317 super(getDelegate());
318 identifier = original;
319 status = TransactionStatus.NEW;
324 * Ensures all subpaths are removed - this currently does slow lookup in
329 public void deepRemoveOperationalData(InstanceIdentifier entry) {
330 Iterable<InstanceIdentifier> paths = getOperationalSubpaths(entry);
331 removeOperationalData(entry);
332 for (InstanceIdentifier potential : paths) {
333 removeOperationalData(potential);
337 public void deepRemoveConfigurationData(InstanceIdentifier entry) {
338 Iterable<InstanceIdentifier> paths = getConfigurationSubpaths(entry);
339 removeConfigurationData(entry);
340 for (InstanceIdentifier potential : paths) {
341 removeConfigurationData(potential);
346 public Object getIdentifier() {
347 return this.identifier;
351 public TransactionStatus getStatus() {
356 public Future<RpcResult<TransactionStatus>> commit() {
357 throw new UnsupportedOperationException("Commit should not be invoked on this");
361 protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored,
362 CompositeNode modified) {
363 return mergeData(path, stored, modified, true);
367 protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored,
368 CompositeNode modified) {
369 return mergeData(path, stored, modified, false);