Merge "Bug 499: Initial implementation of data tree modifications"
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / MutableDataTree.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.md.sal.dom.store.impl;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12
13 import java.util.Map.Entry;
14
15 import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
16 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
17 import org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils;
18 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import com.google.common.base.Optional;
26
27 class MutableDataTree {
28
29     private static final Logger log = LoggerFactory.getLogger(MutableDataTree.class);
30
31     final DataAndMetadataSnapshot snapshot;
32     final NodeModification rootModification;
33     final ModificationApplyOperation strategyTree;
34
35     private  boolean sealed = false;
36
37     private MutableDataTree(final DataAndMetadataSnapshot snapshot, final ModificationApplyOperation strategyTree) {
38         this.snapshot = snapshot;
39         this.strategyTree = strategyTree;
40         this.rootModification = NodeModification.createUnmodified(snapshot.getMetadataTree());
41     }
42
43     public void write(final InstanceIdentifier path, final NormalizedNode<?, ?> value) {
44         checkSealed();
45         resolveModificationFor(path).write(value);
46     }
47
48     public void delete(final InstanceIdentifier path) {
49         checkSealed();
50         resolveModificationFor(path).delete();
51     }
52
53     public Optional<NormalizedNode<?, ?>> read(final InstanceIdentifier path) {
54         Entry<InstanceIdentifier, NodeModification> modification = TreeNodeUtils.findClosest(rootModification, path);
55         return getModifiedVersion(path, modification);
56     }
57
58     private Optional<NormalizedNode<?, ?>> getModifiedVersion(final InstanceIdentifier path, final Entry<InstanceIdentifier, NodeModification> modification) {
59         Optional<StoreMetadataNode> result = resolveSnapshot(modification);
60         if(result.isPresent()) {
61             NormalizedNode<?, ?> data = result.get().getData();
62             return NormalizedNodeUtils.findNode(modification.getKey(),data, path);
63         }
64         return Optional.absent();
65
66     }
67
68     private Optional<StoreMetadataNode> resolveSnapshot(final Entry<InstanceIdentifier, NodeModification> keyModification) {
69         InstanceIdentifier path = keyModification.getKey();
70         NodeModification modification = keyModification.getValue();
71         return resolveSnapshot(path,modification);
72     }
73
74     private Optional<StoreMetadataNode> resolveSnapshot(final InstanceIdentifier path, final NodeModification modification) {
75         try {
76             return resolveModificationStrategy(path).apply(modification,modification.getOriginal());
77         } catch (Exception e) {
78             log.error("Could not create snapshot for {},",e);
79             throw e;
80         }
81     }
82
83     private ModificationApplyOperation resolveModificationStrategy(final InstanceIdentifier path) {
84         log.trace("Resolving modification apply strategy for {}",path);
85         Optional<ModificationApplyOperation> strategy = TreeNodeUtils.findNode(strategyTree, path);
86         checkArgument(strategy.isPresent(),"Provided path %s is not supported by data store. No schema available for it.",path);
87         return strategy.get();
88     }
89
90     private NodeModification resolveModificationFor(final InstanceIdentifier path) {
91         NodeModification modification = rootModification;
92         // We ensure strategy is present.
93         resolveModificationStrategy(path);
94         for (PathArgument pathArg : path.getPath()) {
95             modification = modification.modifyChild(pathArg);
96         }
97         return modification;
98     }
99
100     public static MutableDataTree from(final DataAndMetadataSnapshot snapshot, final ModificationApplyOperation resolver) {
101         return new MutableDataTree(snapshot, resolver);
102     }
103
104     public void seal() {
105         sealed = true;
106         rootModification.seal();
107     }
108
109     private void checkSealed() {
110         checkState(!sealed , "Data Tree is sealed. No further modifications allowed.");
111     }
112 }