3b20b2876f6d8ababb5089c5f0be842d581b1038
[hc2vpp.git] /
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package io.fd.honeycomb.v3po.translate.v3po.util;
18
19 import com.google.common.collect.Lists;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Map;
24 import javax.annotation.Nonnull;
25 import javax.annotation.concurrent.ThreadSafe;
26 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
27 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
28 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
34 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
35 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
36 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
37 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
38 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * Naming context keeping a mapping between int index and string name.
44  * Provides artificial names to unknown indices.
45  */
46 @ThreadSafe
47 public class DataTreeNamingContext extends NamingContext {
48
49     // FIXME this has to be accessed by readers/writers in a transactional manner and the transaction will only be committed once
50     // the Read or Write operation finishes successfully
51     // Context datatree has to become a first class citizen of Honeycomb, and Honeycomb needs to create and provide
52     // context read write transaction as part of context to read/write customizers
53     // This will then become just a utility writer relying on transaction provided by the infrastructure
54     // Btw. the context transaction needs to disable commit/submit when being passed to customizers
55
56     private static final Logger LOG = LoggerFactory.getLogger(DataTreeNamingContext.class);
57
58     private static final QName NAME_KEY_QNAME = QName.create(Contexts.QNAME, "name");
59     private static final QName INDEX_QNAME = QName.create(Contexts.QNAME, "index");
60
61     private final String instanceName;
62     private final DataTree contextDataTree;
63
64     private final YangInstanceIdentifier.NodeIdentifierWithPredicates namingContextNodeId;
65     private final YangInstanceIdentifier namingContextIid;
66
67     public DataTreeNamingContext(final String artificialNamePrefix, final String instanceName,
68                                  final DataTree contextDataTree) {
69         super(artificialNamePrefix);
70         this.instanceName = instanceName;
71         this.contextDataTree = contextDataTree;
72
73         namingContextNodeId = getNodeId(
74             org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME,
75             Collections.singletonMap(NAME_KEY_QNAME, instanceName));
76         namingContextIid = YangInstanceIdentifier.create(
77             getNodeId(Contexts.QNAME),
78             getNodeId(org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME),
79             namingContextNodeId);
80
81         // FIXME read current mappings and initialize map
82         mergeNewContextInDataTree(instanceName);
83     }
84
85     // TODO move the data tree aspect into a dedicated class
86     private void mergeNewContextInDataTree(final String instanceName) {
87         final DataTreeModification dataTreeModification = getModification();
88
89         final YangInstanceIdentifier.NodeIdentifier namingContextsNodeIdForMapNode = getNodeId(
90             org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME);
91
92         final ContainerNode newMapping = Builders.containerBuilder()
93             .withNodeIdentifier(getNodeId(Contexts.QNAME))
94             .withChild(Builders.mapBuilder()
95                 .withNodeIdentifier(namingContextsNodeIdForMapNode)
96                 .withChild(Builders.mapEntryBuilder()
97                     .withNodeIdentifier(namingContextNodeId)
98                     .withChild(ImmutableNodes.leafNode(NAME_KEY_QNAME, instanceName))
99                     .withChild(Builders.containerBuilder()
100                         .withNodeIdentifier(getNodeId(Mappings.QNAME))
101                         .withChild(Builders.mapBuilder()
102                             .withNodeIdentifier(getNodeId(Mapping.QNAME))
103                             .build())
104                         .build())
105                     .build())
106                 .build())
107             .build();
108
109         // FIXME add logs or debug to resolve:
110 //        2016-05-13 15:48:52,401 | WARN  | config-pusher    | DataTreeNamingContext            | 240 - io.fd.honeycomb.v3po.vpp-translate-utils - 1.0.0.SNAPSHOT | Unable to update context: interface-context in context data tree
111 //        org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException: Node /(urn:honeycomb:params:xml:ns:yang:naming:context?revision=2016-05-13)contexts/naming-context/naming-context[{(urn:honeycomb:params:xml:ns:yang:naming:context?revision=2016-05-13)name=interface-context}] does not exist. Cannot apply modification to its children.
112 //        at org.opendaylight.yangtools.yang.data.impl.schema.tree.AbstractNodeContainerModificationStrategy.checkTouchApplicable(AbstractNodeContainerModificationStrategy.java:276)[55:org.opendaylight.yangtools.yang-data-impl:0.8.0.Beryllium]
113         // FIXME looks like a timing issue, did not occur when debugging
114
115         dataTreeModification.merge(YangInstanceIdentifier.create(getNodeId(Contexts.QNAME)), newMapping);
116
117         commitModification(dataTreeModification);
118     }
119
120     private void commitModification(final DataTreeModification dataTreeModification) {
121         try {
122             dataTreeModification.ready();
123             contextDataTree.validate(dataTreeModification);
124             contextDataTree.commit(contextDataTree.prepare(dataTreeModification));
125         } catch (DataValidationFailedException e) {
126             LOG.warn("Unable to update context: {} in context data tree", instanceName, e);
127             throw new IllegalStateException("Unable to update context in context data tree", e);
128         }
129     }
130
131     private DataTreeModification getModification() {
132         final DataTreeSnapshot dataTreeSnapshot = contextDataTree.takeSnapshot();
133         return dataTreeSnapshot.newModification();
134     }
135
136     private static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeId(@Nonnull final QName qName,
137                                                                                  @Nonnull final Map<QName, Object> keys) {
138         return new YangInstanceIdentifier.NodeIdentifierWithPredicates(qName, keys);
139     }
140
141     private static YangInstanceIdentifier.NodeIdentifier getNodeId(@Nonnull final QName qName) {
142         return new YangInstanceIdentifier.NodeIdentifier(qName);
143     }
144
145     public synchronized void addName(final int index, final String name) {
146         addMappingToDataTree(name, index);
147         super.addName(index, name);
148     }
149
150     private void addMappingToDataTree(final String name, final int index) {
151         final DataTreeModification dataTreeModification = getModification();
152
153         final YangInstanceIdentifier.NodeIdentifierWithPredicates mappingNodeId = getNodeId(Mapping.QNAME,
154             Collections.singletonMap(NAME_KEY_QNAME, name));
155
156         final List<YangInstanceIdentifier.PathArgument> pathArguments = namingContextIid.getPathArguments();
157         final ArrayList<YangInstanceIdentifier.PathArgument> newPathArgs = Lists.newArrayList(pathArguments);
158         newPathArgs.add(getNodeId(Mappings.QNAME));
159         newPathArgs.add(getNodeId(Mapping.QNAME));
160         newPathArgs.add(mappingNodeId);
161
162         final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(newPathArgs);
163
164         final NormalizedNode<?, ?> newMapping = Builders.mapEntryBuilder()
165             .withNodeIdentifier(mappingNodeId)
166             .withChild(ImmutableNodes.leafNode(NAME_KEY_QNAME, name))
167             .withChild(ImmutableNodes.leafNode(INDEX_QNAME, index))
168             .build();
169
170         dataTreeModification.write(identifier, newMapping);
171
172         commitModification(dataTreeModification);
173     }
174
175     public synchronized int removeName(@Nonnull final String name) {
176         removeMappingFromDataTree(name);
177         return super.removeName(name);
178     }
179
180     private void removeMappingFromDataTree(final String name) {
181         final DataTreeModification dataTreeModification = getModification();
182
183         final YangInstanceIdentifier.NodeIdentifierWithPredicates mappingNodeId = getNodeId(Mapping.QNAME,
184             Collections.singletonMap(NAME_KEY_QNAME, name));
185
186         final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(
187             namingContextIid.getLastPathArgument(), getNodeId(Mappings.QNAME), getNodeId(Mapping.QNAME), mappingNodeId);
188
189         dataTreeModification.delete(identifier);
190
191         commitModification(dataTreeModification);
192     }
193 }