2 * Copyright (c) 2016 Cisco and/or its affiliates.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package io.fd.honeycomb.v3po.data.impl;
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.Iterables.getOnlyElement;
22 import com.google.common.base.Function;
23 import com.google.common.base.Optional;
24 import com.google.common.base.Preconditions;
25 import com.google.common.collect.Collections2;
26 import com.google.common.collect.Multimap;
27 import com.google.common.util.concurrent.CheckedFuture;
28 import com.google.common.util.concurrent.Futures;
29 import io.fd.honeycomb.v3po.data.ReadableDataTree;
30 import io.fd.honeycomb.v3po.translate.Context;
31 import io.fd.honeycomb.v3po.translate.read.ReadContext;
32 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
33 import io.fd.honeycomb.v3po.translate.read.ReaderRegistry;
34 import java.util.Collection;
36 import javax.annotation.Nonnull;
37 import javax.annotation.Nullable;
38 import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
39 import org.opendaylight.yangtools.yang.binding.DataObject;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
42 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
44 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
47 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
49 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
50 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
51 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
52 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
54 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
59 * ReadableDataTree implementation for operational data.
61 public final class OperationalDataTree implements ReadableDataTree {
62 private static final Logger LOG = LoggerFactory.getLogger(OperationalDataTree.class);
64 private final BindingNormalizedNodeSerializer serializer;
65 private final ReaderRegistry readerRegistry;
66 private final SchemaContext globalContext;
69 * Creates operational data tree instance.
71 * @param serializer service for serialization between Java Binding Data representation and NormalizedNode
73 * @param globalContext service for obtaining top level context data from all yang modules.
74 * @param readerRegistry service responsible for translation between DataObjects and data provider.
76 public OperationalDataTree(@Nonnull BindingNormalizedNodeSerializer serializer,
77 @Nonnull final SchemaContext globalContext, @Nonnull ReaderRegistry readerRegistry) {
78 this.globalContext = checkNotNull(globalContext, "globalContext should not be null");
79 this.serializer = checkNotNull(serializer, "serializer should not be null");
80 this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null");
84 public CheckedFuture<Optional<NormalizedNode<?, ?>>,
85 org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read(
86 @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) {
88 try(ReadContext ctx = new ReadContextImpl()) {
89 if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) {
90 return Futures.immediateCheckedFuture(readRoot(ctx));
92 return Futures.immediateCheckedFuture(readNode(yangInstanceIdentifier, ctx));
94 } catch (ReadFailedException e) {
95 return Futures.immediateFailedCheckedFuture(
96 new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(
97 "Failed to read VPP data", e));
101 private Optional<NormalizedNode<?, ?>> readNode(final YangInstanceIdentifier yangInstanceIdentifier,
102 final ReadContext ctx)
103 throws ReadFailedException {
104 LOG.debug("OperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier);
105 final InstanceIdentifier<?> path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier);
106 checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier);
107 LOG.debug("OperationalDataTree.readNode(), path={}", path);
109 final Optional<? extends DataObject> dataObject;
111 dataObject = readerRegistry.read(path, ctx);
112 if (dataObject.isPresent()) {
113 final NormalizedNode<?, ?> value = toNormalizedNodeFunction(path).apply(dataObject.get());
114 return Optional.<NormalizedNode<?, ?>>fromNullable(value);
116 return Optional.absent();
120 private Optional<NormalizedNode<?, ?>> readRoot(final ReadContext ctx) throws ReadFailedException {
121 LOG.debug("OperationalDataTree.readRoot()");
123 final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> dataNodeBuilder =
124 Builders.containerBuilder()
125 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME));
127 final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> dataObjects =
128 readerRegistry.readAll(ctx);
130 for (final InstanceIdentifier<? extends DataObject> instanceIdentifier : dataObjects.keySet()) {
131 final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier);
132 final NormalizedNode<?, ?> node =
133 wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier));
134 dataNodeBuilder.withChild((DataContainerChild<?, ?>) node);
137 return Optional.<NormalizedNode<?, ?>>of(dataNodeBuilder.build());
140 private NormalizedNode<?, ?> wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier,
141 final InstanceIdentifier<? extends DataObject> instanceIdentifier,
142 final Collection<? extends DataObject> dataObjects) {
143 final Collection<NormalizedNode<?, ?>> normalizedRootElements = Collections2
144 .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier));
146 final DataSchemaNode schemaNode =
147 globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType());
148 if (schemaNode instanceof ListSchemaNode) {
149 // In case of a list, wrap all the values in a Mixin parent node
150 final ListSchemaNode listSchema = (ListSchemaNode) schemaNode;
151 return wrapListIntoMixinNode(normalizedRootElements, listSchema);
153 Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected");
154 return getOnlyElement(normalizedRootElements);
158 private static DataContainerChild<?, ?> wrapListIntoMixinNode(
159 final Collection<NormalizedNode<?, ?>> normalizedRootElements, final ListSchemaNode listSchema) {
160 if (listSchema.getKeyDefinition().isEmpty()) {
161 final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> listBuilder =
162 Builders.unkeyedListBuilder();
163 for (NormalizedNode<?, ?> normalizedRootElement : normalizedRootElements) {
164 listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement);
166 return listBuilder.build();
168 final CollectionNodeBuilder<MapEntryNode, ? extends MapNode> listBuilder =
169 listSchema.isUserOrdered()
170 ? Builders.orderedMapBuilder()
171 : Builders.mapBuilder();
173 for (NormalizedNode<?, ?> normalizedRootElement : normalizedRootElements) {
174 listBuilder.withChild((MapEntryNode) normalizedRootElement);
176 return listBuilder.build();
180 @SuppressWarnings("unchecked")
181 private Function<DataObject, NormalizedNode<?, ?>> toNormalizedNodeFunction(final InstanceIdentifier path) {
182 return new Function<DataObject, NormalizedNode<?, ?>>() {
184 public NormalizedNode<?, ?> apply(@Nullable final DataObject dataObject) {
185 LOG.trace("OperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject);
186 final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry =
187 serializer.toNormalizedNode(path, dataObject);
189 LOG.trace("OperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry);
190 return entry.getValue();
195 private static final class ReadContextImpl implements ReadContext {
196 public final Context ctx = new Context();
200 public Context getContext() {
205 public void close() {
206 // Make sure to clear the storage in case some customizer stored it to prevent memory leaks