2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.binding.util;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import com.google.common.base.Optional;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableMap.Builder;
15 import java.lang.reflect.InvocationTargetException;
16 import java.lang.reflect.Method;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Iterator;
20 import java.util.List;
22 import java.util.Map.Entry;
23 import org.opendaylight.yangtools.yang.binding.Augmentable;
24 import org.opendaylight.yangtools.yang.binding.Augmentation;
25 import org.opendaylight.yangtools.yang.binding.InterfaceTyped;
26 import org.opendaylight.yangtools.yang.binding.TreeNode;
27 import org.opendaylight.yangtools.yang.binding.IdentifiableListItem;
28 import org.opendaylight.yangtools.yang.binding.Identifier;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
34 public class DataObjectReadingUtil {
36 private DataObjectReadingUtil() {
37 throw new UnsupportedOperationException("Utility class. Instantion is not allowed.");
43 * Parent object on which read operation will be performed
45 * Path, to parent object.
47 * Path, which is nested to parent, and should be readed.
48 * @return Value of object.
50 public static final <T extends TreeNode, P extends TreeNode> Map<InstanceIdentifier<T>, T> readData(final P parent,
51 final InstanceIdentifier<P> parentPath, final InstanceIdentifier<T> childPath) {
52 checkArgument(parent != null, "Parent must not be null.");
53 checkArgument(parentPath != null, "Parent path must not be null");
54 checkArgument(childPath != null, "Child path must not be null");
55 checkArgument(parentPath.containsWildcarded(childPath), "Parent object must be parent of child.");
57 List<PathArgument> pathArgs = subList(parentPath.getPathArguments(), childPath.getPathArguments());
58 @SuppressWarnings("rawtypes")
59 Map<InstanceIdentifier, InterfaceTyped> lastFound = Collections
60 .<InstanceIdentifier, InterfaceTyped> singletonMap(parentPath, parent);
61 for (PathArgument pathArgument : pathArgs) {
62 @SuppressWarnings("rawtypes")
63 final ImmutableMap.Builder<InstanceIdentifier, InterfaceTyped> potentialBuilder = ImmutableMap.builder();
64 for (@SuppressWarnings("rawtypes")
65 Entry<InstanceIdentifier, InterfaceTyped> entry : lastFound.entrySet()) {
66 potentialBuilder.putAll(readData(entry, pathArgument));
68 lastFound = potentialBuilder.build();
69 if (lastFound.isEmpty()) {
70 return Collections.emptyMap();
73 @SuppressWarnings({ "unchecked", "rawtypes" })
74 final Map<InstanceIdentifier<T>, T> result = (Map) lastFound;
78 @SuppressWarnings("rawtypes")
79 private static Map<InstanceIdentifier, InterfaceTyped> readData(final Entry<InstanceIdentifier, InterfaceTyped> entry,
80 final PathArgument pathArgument) {
81 return readData(entry.getValue(), entry.getKey(), pathArgument);
84 public static final <T extends TreeNode> Optional<T> readData(final TreeNode source, final Class<T> child) {
85 checkArgument(source != null, "Object should not be null.");
86 checkArgument(child != null, "Child type should not be null");
87 Class<? extends InterfaceTyped> parentClass = source.implementedInterface();
89 @SuppressWarnings("unchecked")
90 T potential = (T) resolveReadStrategy(parentClass, child).read(source, child);
91 return Optional.fromNullable(potential);
94 @SuppressWarnings("rawtypes")
95 private static final Map<InstanceIdentifier, InterfaceTyped> readData(final InterfaceTyped parent,
96 final InstanceIdentifier parentPath, final PathArgument child) {
97 checkArgument(parent != null, "Object should not be null.");
98 checkArgument(child != null, "Child argument should not be null");
99 Class<? extends InterfaceTyped> parentClass = parent.implementedInterface();
100 return resolveReadStrategy(parentClass, child.getType()).readUsingPathArgument(parent, child, parentPath);
103 private static DataObjectReadingStrategy resolveReadStrategy(final Class<? extends InterfaceTyped> parentClass,
104 final Class<? extends InterfaceTyped> type) {
106 DataObjectReadingStrategy strategy = createReadStrategy(parentClass, type);
107 // FIXME: Add caching of strategies
111 private static DataObjectReadingStrategy createReadStrategy(final Class<? extends InterfaceTyped> parent,
112 final Class<? extends InterfaceTyped> child) {
114 if (Augmentable.class.isAssignableFrom(parent) && Augmentation.class.isAssignableFrom(child)) {
115 return REAUSABLE_AUGMENTATION_READING_STRATEGY;
119 * FIXME Ensure that this strategies also works for children of cases.
120 * Possible edge-case is : Parent container uses grouping foo case is
121 * added by augmentation also uses foo.
123 if (IdentifiableListItem.class.isAssignableFrom(child)) {
124 @SuppressWarnings("unchecked")
125 final Class<? extends IdentifiableListItem<?>> identifiableClass = (Class<? extends IdentifiableListItem<?>>) child;
126 return new ListItemReadingStrategy(parent, identifiableClass);
128 return new ContainerReadingStrategy(parent, child);
131 private static Method resolveGetterMethod(final Class<? extends InterfaceTyped> parent, final Class<?> child) {
132 String methodName = "get" + child.getSimpleName();
134 return parent.getMethod(methodName);
135 } catch (NoSuchMethodException e) {
136 throw new IllegalArgumentException(e);
137 } catch (SecurityException e) {
138 throw new IllegalStateException(e);
142 @SuppressWarnings("rawtypes")
143 private static abstract class DataObjectReadingStrategy {
145 private final Class<? extends InterfaceTyped> parentType;
146 private final Class<? extends InterfaceTyped> childType;
147 private final Method getterMethod;
149 @SuppressWarnings("unchecked")
150 public DataObjectReadingStrategy(final Class parentType, final Class childType) {
151 checkArgument(InterfaceTyped.class.isAssignableFrom(parentType));
152 checkArgument(InterfaceTyped.class.isAssignableFrom(childType));
153 this.parentType = parentType;
154 this.childType = childType;
155 this.getterMethod = resolveGetterMethod(parentType, childType);
158 @SuppressWarnings("unchecked")
159 public DataObjectReadingStrategy(final Class parentType, final Class childType, final Method getter) {
160 this.parentType = parentType;
161 this.childType = childType;
162 this.getterMethod = getter;
165 @SuppressWarnings("unused")
166 protected Class<? extends InterfaceTyped> getParentType() {
170 protected Class<? extends InterfaceTyped> getChildType() {
174 protected Method getGetterMethod() {
178 public abstract Map<InstanceIdentifier, InterfaceTyped> readUsingPathArgument(InterfaceTyped parent,
179 PathArgument childArgument, InstanceIdentifier targetBuilder);
181 public abstract InterfaceTyped read(InterfaceTyped parent, Class<?> childType);
185 @SuppressWarnings("rawtypes")
186 private static class ContainerReadingStrategy extends DataObjectReadingStrategy {
188 public ContainerReadingStrategy(final Class<? extends InterfaceTyped> parent, final Class<? extends InterfaceTyped> child) {
189 super(parent, child);
190 checkArgument(child.isAssignableFrom(getGetterMethod().getReturnType()));
194 public Map<InstanceIdentifier, InterfaceTyped> readUsingPathArgument(final InterfaceTyped parent,
195 final PathArgument childArgument, final InstanceIdentifier parentPath) {
196 final InterfaceTyped result = read(parent, childArgument.getType());
197 if (result != null) {
198 @SuppressWarnings("unchecked")
199 InstanceIdentifier childPath = parentPath.child(childArgument.getType());
200 return Collections.singletonMap(childPath, result);
202 return Collections.emptyMap();
206 public InterfaceTyped read(final InterfaceTyped parent, final Class<?> childType) {
208 Object potentialData = getGetterMethod().invoke(parent);
209 checkState(potentialData instanceof InterfaceTyped);
210 return (InterfaceTyped) potentialData;
212 } catch (IllegalAccessException | InvocationTargetException e) {
213 throw new IllegalArgumentException(e);
218 @SuppressWarnings("rawtypes")
219 private static class ListItemReadingStrategy extends DataObjectReadingStrategy {
221 public ListItemReadingStrategy(final Class<? extends InterfaceTyped> parent, final Class child) {
222 super(parent, child);
223 checkArgument(Iterable.class.isAssignableFrom(getGetterMethod().getReturnType()));
227 public InterfaceTyped read(final InterfaceTyped parent, final Class<?> childType) {
228 // This will always fail since we do not have key.
232 @SuppressWarnings("unchecked")
234 public Map<InstanceIdentifier, InterfaceTyped> readUsingPathArgument(final InterfaceTyped parent,
235 final PathArgument childArgument, final InstanceIdentifier builder) {
237 Object potentialList = getGetterMethod().invoke(parent);
238 if (potentialList instanceof Iterable) {
240 final Iterable<IdentifiableListItem> dataList = (Iterable<IdentifiableListItem>) potentialList;
241 if (childArgument instanceof IdentifiableItem<?, ?>) {
242 return readUsingIdentifiableItem(dataList, (IdentifiableItem) childArgument, builder);
244 return readAll(dataList, builder);
247 } catch (InvocationTargetException e) {
248 throw new IllegalStateException(e);
249 } catch (IllegalAccessException e) {
250 throw new IllegalStateException(e);
251 } catch (IllegalArgumentException e) {
252 throw new IllegalStateException(e);
254 return Collections.emptyMap();
257 private Map<InstanceIdentifier, InterfaceTyped> readAll(final Iterable<IdentifiableListItem> dataList,
258 final InstanceIdentifier parentPath) {
259 Builder<InstanceIdentifier, InterfaceTyped> result = ImmutableMap
260 .<InstanceIdentifier, InterfaceTyped> builder();
261 for (IdentifiableListItem item : dataList) {
262 @SuppressWarnings("unchecked")
263 InstanceIdentifier childPath = parentPath.child(getChildType(), item.identifier());
264 result.put(childPath, (InterfaceTyped) item);
266 return result.build();
269 @SuppressWarnings("unchecked")
270 private static Map<InstanceIdentifier, InterfaceTyped> readUsingIdentifiableItem(final Iterable<IdentifiableListItem> dataList,
271 final IdentifiableItem childArgument, final InstanceIdentifier parentPath) {
272 final Identifier<?> key = childArgument.getKey();
273 for (IdentifiableListItem item : dataList) {
274 if (key.equals(item.identifier()) && item instanceof InterfaceTyped) {
275 checkState(childArgument.getType().isInstance(item),
276 "Found child is not instance of requested type");
277 InstanceIdentifier childPath = parentPath
278 .child(childArgument.getType(), item.identifier());
279 return Collections.singletonMap(childPath, (InterfaceTyped) item);
282 return Collections.emptyMap();
287 private static final DataObjectReadingStrategy REAUSABLE_AUGMENTATION_READING_STRATEGY = new AugmentationReadingStrategy();
289 private static final class AugmentationReadingStrategy extends DataObjectReadingStrategy {
291 public AugmentationReadingStrategy() {
292 super(Augmentable.class, Augmentation.class, null);
295 @SuppressWarnings("rawtypes")
297 public Map<InstanceIdentifier, InterfaceTyped> readUsingPathArgument(final InterfaceTyped parent,
298 final PathArgument childArgument, final InstanceIdentifier builder) {
299 checkArgument(childArgument instanceof Item<?>, "Path Argument must be Item without keys");
300 InterfaceTyped aug = read(parent, childArgument.getType());
302 @SuppressWarnings("unchecked")
303 final InstanceIdentifier childPath = builder.child(childArgument.getType());
304 return Collections.singletonMap(childPath, aug);
306 return Collections.emptyMap();
311 public InterfaceTyped read(final InterfaceTyped parent, final Class<?> childType) {
312 checkArgument(Augmentation.class.isAssignableFrom(childType), "Parent must be Augmentable.");
313 checkArgument(parent instanceof Augmentable<?>, "Parent must be Augmentable.");
315 @SuppressWarnings({ "rawtypes", "unchecked" })
316 Augmentation potential = ((Augmentable) parent).getAugmentation(childType);
317 checkState(potential instanceof InterfaceTyped, "Readed augmention must be data object");
318 return (InterfaceTyped) potential;
323 * Create sublist view of child from element on [size-of-parent] position to
328 * @return sublist view of child argument
329 * @throws IllegalArgumentException
330 * if parent argument is bigger than child
332 private static <P, C> List<C> subList(final Iterable<P> parent, final Iterable<C> child) {
333 Iterator<P> iParent = parent.iterator();
334 List<C> result = new ArrayList<>();
335 for (C arg : child) {
336 if (iParent.hasNext()) {
342 if (iParent.hasNext()) {
343 throw new IllegalArgumentException("Parent argument is bigger than child.");