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