64ecaf09550078db22977355264148e7429567a0
[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.util.read.registry;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20
21 import com.google.common.base.Optional;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.collect.Iterables;
24 import io.fd.honeycomb.v3po.translate.read.ListReader;
25 import io.fd.honeycomb.v3po.translate.read.ReadContext;
26 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
27 import io.fd.honeycomb.v3po.translate.read.Reader;
28 import io.fd.honeycomb.v3po.translate.util.RWUtils;
29 import io.fd.honeycomb.v3po.translate.util.read.AbstractGenericReader;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import javax.annotation.Nonnull;
34 import org.opendaylight.yangtools.concepts.Builder;
35 import org.opendaylight.yangtools.yang.binding.DataObject;
36 import org.opendaylight.yangtools.yang.binding.Identifiable;
37 import org.opendaylight.yangtools.yang.binding.Identifier;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 class CompositeReader<D extends DataObject, B extends Builder<D>> extends AbstractGenericReader<D, B> {
43
44     private static final Logger LOG = LoggerFactory.getLogger(CompositeReader.class);
45
46     private final Reader<D, B> delegate;
47     private final ImmutableMap<Class<?>, Reader<? extends DataObject, ? extends Builder<?>>> childReaders;
48
49     private CompositeReader(final Reader<D, B> reader,
50                             final ImmutableMap<Class<?>, Reader<? extends DataObject, ? extends Builder<?>>> childReaders) {
51         super(reader.getManagedDataObjectType());
52         this.delegate = reader;
53         this.childReaders = childReaders;
54     }
55
56     @SuppressWarnings("unchecked")
57     public static <D extends DataObject> InstanceIdentifier<D> appendTypeToId(
58         final InstanceIdentifier<? extends DataObject> parentId, final InstanceIdentifier<D> type) {
59         final InstanceIdentifier.PathArgument t = new InstanceIdentifier.Item<>(type.getTargetType());
60         return (InstanceIdentifier<D>) InstanceIdentifier.create(Iterables.concat(
61             parentId.getPathArguments(), Collections.singleton(t)));
62     }
63
64     @Nonnull
65     @Override
66     public Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id,
67                                                @Nonnull final ReadContext ctx) throws ReadFailedException {
68         if (shouldReadCurrent(id)) {
69             return readCurrent((InstanceIdentifier<D>) id, ctx);
70         } else if (shouldDelegateToChild(id)) {
71             return readSubtree(id, ctx);
72         } else {
73             // Fallback
74             return delegate.read(id, ctx);
75         }
76     }
77
78     private boolean shouldReadCurrent(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
79         return id.getTargetType().equals(getManagedDataObjectType().getTargetType());
80     }
81
82     private boolean shouldDelegateToChild(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
83         return childReaders.containsKey(RWUtils.getNextId(id, getManagedDataObjectType()).getType());
84     }
85
86     private Optional<? extends DataObject> readSubtree(final InstanceIdentifier<? extends DataObject> id,
87                                                        final ReadContext ctx) throws ReadFailedException {
88         final InstanceIdentifier.PathArgument nextId = RWUtils.getNextId(id, getManagedDataObjectType());
89         final Reader<?, ? extends Builder<?>> nextReader = childReaders.get(nextId.getType());
90         checkArgument(nextReader != null, "Unable to read: %s. No delegate present, available readers at next level: %s",
91                 id, childReaders.keySet());
92         return nextReader.read(id, ctx);
93     }
94
95     @SuppressWarnings("unchecked")
96     private void readChildren(final InstanceIdentifier<D> id, @Nonnull final ReadContext ctx, final B builder)
97             throws ReadFailedException {
98         for (Reader child : childReaders.values()) {
99             LOG.debug("{}: Reading child node from: {}", this, child);
100             final InstanceIdentifier childId = appendTypeToId(id, child.getManagedDataObjectType());
101
102             if (child instanceof ListReader) {
103                 final List<? extends DataObject> list = ((ListReader) child).readList(childId, ctx);
104                 ((ListReader) child).merge(builder, list);
105             } else {
106                 final Optional<? extends DataObject> read = child.read(childId, ctx);
107                 if (read.isPresent()) {
108                     child.merge(builder, read.get());
109                 }
110             }
111         }
112     }
113
114     @Override
115     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final B builder,
116                                       @Nonnull final ReadContext ctx)
117             throws ReadFailedException {
118         delegate.readCurrentAttributes(id, builder, ctx);
119         readChildren(id, ctx, builder);
120     }
121
122     @Nonnull
123     @Override
124     public B getBuilder(final InstanceIdentifier<D> id) {
125         return delegate.getBuilder(id);
126     }
127
128     @Override
129     public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final D readValue) {
130         delegate.merge(parentBuilder, readValue);
131     }
132
133     /**
134      * Wrap a Reader as a Composite Reader.
135      */
136     static <D extends DataObject, B extends Builder<D>> Reader<D, B> createForReader(
137             @Nonnull final Reader<D, B> reader,
138             @Nonnull final ImmutableMap<Class<?>, Reader<?, ? extends Builder<?>>> childReaders) {
139
140         return (reader instanceof ListReader)
141                 ? new CompositeListReader<>((ListReader) reader, childReaders)
142                 : new CompositeReader<>(reader, childReaders);
143     }
144
145     private static class CompositeListReader<D extends DataObject & Identifiable<K>, B extends Builder<D>, K extends Identifier<D>>
146             extends CompositeReader<D, B>
147             implements ListReader<D, K, B> {
148
149         private final ListReader<D, K, B> delegate;
150
151         private CompositeListReader(final ListReader<D, K, B> reader,
152                                     final ImmutableMap<Class<?>, Reader<? extends DataObject, ? extends Builder<?>>> childReaders) {
153             super(reader, childReaders);
154             this.delegate = reader;
155         }
156
157         @Nonnull
158         @Override
159         public List<D> readList(@Nonnull final InstanceIdentifier<D> id, @Nonnull final ReadContext ctx)
160                 throws ReadFailedException {
161             LOG.trace("{}: Reading all list entries", this);
162             final List<K> allIds = delegate.getAllIds(id, ctx);
163             LOG.debug("{}: Reading list entries for: {}", this, allIds);
164
165             // Override read list in order to perform readCurrent + readChildren here
166             final ArrayList<D> allEntries = new ArrayList<>(allIds.size());
167             for (K key : allIds) {
168                 final InstanceIdentifier.IdentifiableItem<D, K> currentBdItem = RWUtils.getCurrentIdItem(id, key);
169                 final InstanceIdentifier<D> keyedId = RWUtils.replaceLastInId(id, currentBdItem);
170                 final Optional<D> read = readCurrent(keyedId, ctx);
171                 if (read.isPresent()) {
172                     final DataObject singleItem = read.get();
173                     checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass()));
174                     allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem));
175                 }
176             }
177             return allEntries;
178         }
179
180         @Override
181         public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<D> readData) {
182             delegate.merge(builder, readData);
183         }
184
185         @Override
186         public List<K> getAllIds(@Nonnull final InstanceIdentifier<D> id,
187                                  @Nonnull final ReadContext ctx) throws ReadFailedException {
188             return delegate.getAllIds(id, ctx);
189         }
190     }
191
192 }