Bug 499: Initial draft of in-memory datastore and data broker
[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,
59             final Entry<InstanceIdentifier, NodeModification> modification) {
60         Optional<StoreMetadataNode> result = resolveSnapshot(modification);
61         if (result.isPresent()) {
62             NormalizedNode<?, ?> data = result.get().getData();
63             return NormalizedNodeUtils.findNode(modification.getKey(), data, path);
64         }
65         return Optional.absent();
66
67     }
68
69     private Optional<StoreMetadataNode> resolveSnapshot(
70             final Entry<InstanceIdentifier, NodeModification> keyModification) {
71         InstanceIdentifier path = keyModification.getKey();
72         NodeModification modification = keyModification.getValue();
73         return resolveSnapshot(path, modification);
74     }
75
76     private Optional<StoreMetadataNode> resolveSnapshot(final InstanceIdentifier path,
77             final NodeModification modification) {
78         try {
79             return resolveModificationStrategy(path).apply(modification, modification.getOriginal(),
80                     StoreUtils.increase(snapshot.getMetadataTree().getSubtreeVersion()));
81         } catch (Exception e) {
82             log.error("Could not create snapshot for {},", e);
83             throw e;
84         }
85     }
86
87     private ModificationApplyOperation resolveModificationStrategy(final InstanceIdentifier path) {
88         log.trace("Resolving modification apply strategy for {}", path);
89         Optional<ModificationApplyOperation> strategy = TreeNodeUtils.findNode(strategyTree, path);
90         checkArgument(strategy.isPresent(),
91                 "Provided path %s is not supported by data store. No schema available for it.", path);
92         return strategy.get();
93     }
94
95     private OperationWithModification resolveModificationFor(final InstanceIdentifier path) {
96         NodeModification modification = rootModification;
97         // We ensure strategy is present.
98         ModificationApplyOperation operation = resolveModificationStrategy(path);
99         for (PathArgument pathArg : path.getPath()) {
100             modification = modification.modifyChild(pathArg);
101         }
102         return OperationWithModification.from(operation, modification);
103     }
104
105     public static MutableDataTree from(final DataAndMetadataSnapshot snapshot, final ModificationApplyOperation resolver) {
106         return new MutableDataTree(snapshot, resolver);
107     }
108
109     public void seal() {
110         sealed = true;
111         rootModification.seal();
112     }
113
114     private void checkSealed() {
115         checkState(!sealed, "Data Tree is sealed. No further modifications allowed.");
116     }
117
118     protected NodeModification getRootModification() {
119         return rootModification;
120     }
121 }