2 * Copyright (c) 2014 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.DataContainer;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.binding.Identifiable;
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 static final DataObjectReadingStrategy REAUSABLE_AUGMENTATION_READING_STRATEGY = new AugmentationReadingStrategy();
38 private DataObjectReadingUtil() {
39 throw new UnsupportedOperationException("Utility class. Instantion is not allowed.");
45 * Parent object on which read operation will be performed
47 * Path, to parent object.
49 * Path, which is nested to parent, and should be readed.
50 * @return Value of object.
52 public static final <T extends DataObject, P extends DataObject> Map<InstanceIdentifier<T>, T> readData(final P parent,
53 final InstanceIdentifier<P> parentPath, final InstanceIdentifier<T> childPath) {
54 checkArgument(parent != null, "Parent must not be null.");
55 checkArgument(parentPath != null, "Parent path must not be null");
56 checkArgument(childPath != null, "Child path must not be null");
57 checkArgument(parentPath.containsWildcarded(childPath), "Parent object must be parent of child.");
59 List<PathArgument> pathArgs = subList(parentPath.getPathArguments(), childPath.getPathArguments());
60 @SuppressWarnings("rawtypes")
61 Map<InstanceIdentifier, DataContainer> lastFound = Collections
62 .<InstanceIdentifier, DataContainer> singletonMap(parentPath, parent);
63 for (PathArgument pathArgument : pathArgs) {
64 @SuppressWarnings("rawtypes")
65 final ImmutableMap.Builder<InstanceIdentifier, DataContainer> potentialBuilder = ImmutableMap.builder();
66 for (@SuppressWarnings("rawtypes")
67 Entry<InstanceIdentifier, DataContainer> entry : lastFound.entrySet()) {
68 potentialBuilder.putAll(readData(entry, pathArgument));
70 lastFound = potentialBuilder.build();
71 if (lastFound.isEmpty()) {
72 return Collections.emptyMap();
75 @SuppressWarnings({ "unchecked", "rawtypes" })
76 final Map<InstanceIdentifier<T>, T> result = (Map) lastFound;
80 @SuppressWarnings("rawtypes")
81 private static Map<InstanceIdentifier, DataContainer> readData(final Entry<InstanceIdentifier, DataContainer> entry,
82 final PathArgument pathArgument) {
83 return readData(entry.getValue(), entry.getKey(), pathArgument);
86 public static final <T extends DataObject> Optional<T> readData(final DataObject source, final Class<T> child) {
87 checkArgument(source != null, "Object should not be null.");
88 checkArgument(child != null, "Child type should not be null");
89 Class<? extends DataContainer> parentClass = source.getImplementedInterface();
91 @SuppressWarnings("unchecked")
92 T potential = (T) resolveReadStrategy(parentClass, child).read(source, child);
93 return Optional.fromNullable(potential);
96 @SuppressWarnings("rawtypes")
97 private static final Map<InstanceIdentifier, DataContainer> readData(final DataContainer parent,
98 final InstanceIdentifier parentPath, final PathArgument child) {
99 checkArgument(parent != null, "Object should not be null.");
100 checkArgument(child != null, "Child argument should not be null");
101 Class<? extends DataContainer> parentClass = parent.getImplementedInterface();
102 return resolveReadStrategy(parentClass, child.getType()).readUsingPathArgument(parent, child, parentPath);
105 private static DataObjectReadingStrategy resolveReadStrategy(final Class<? extends DataContainer> parentClass,
106 final Class<? extends DataContainer> type) {
108 // FIXME: Add caching of strategies
109 return createReadStrategy(parentClass, type);
112 private static DataObjectReadingStrategy createReadStrategy(final Class<? extends DataContainer> parent,
113 final Class<? extends DataContainer> child) {
115 if (Augmentable.class.isAssignableFrom(parent) && Augmentation.class.isAssignableFrom(child)) {
116 return REAUSABLE_AUGMENTATION_READING_STRATEGY;
120 * FIXME Ensure that this strategies also works for children of cases.
121 * Possible edge-case is : Parent container uses grouping foo case is
122 * added by augmentation also uses foo.
124 if (Identifiable.class.isAssignableFrom(child)) {
125 @SuppressWarnings("unchecked")
126 final Class<? extends Identifiable<?>> identifiableClass = (Class<? extends Identifiable<?>>) child;
127 return new ListItemReadingStrategy(parent, identifiableClass);
129 return new ContainerReadingStrategy(parent, child);
132 @SuppressWarnings("rawtypes")
133 private abstract static class DataObjectReadingStrategy {
135 private final Class<? extends DataContainer> parentType;
136 private final Class<? extends DataContainer> childType;
137 private final Method getterMethod;
139 @SuppressWarnings("unchecked")
140 public DataObjectReadingStrategy(final Class parentType, final Class childType) {
142 checkArgument(DataContainer.class.isAssignableFrom(parentType));
143 checkArgument(DataContainer.class.isAssignableFrom(childType));
144 this.parentType = parentType;
145 this.childType = childType;
146 this.getterMethod = resolveGetterMethod(parentType, childType);
149 @SuppressWarnings("unchecked")
150 public DataObjectReadingStrategy(final Class parentType, final Class childType, final Method getter) {
151 this.parentType = parentType;
152 this.childType = childType;
153 this.getterMethod = getter;
156 @SuppressWarnings("unused")
157 protected Class<? extends DataContainer> getParentType() {
161 protected Class<? extends DataContainer> getChildType() {
165 protected Method getGetterMethod() {
169 public abstract Map<InstanceIdentifier, DataContainer> readUsingPathArgument(DataContainer parent,
170 PathArgument childArgument, InstanceIdentifier targetBuilder);
172 public abstract DataContainer read(DataContainer parent, Class<?> childType);
174 private static Method resolveGetterMethod(final Class<? extends DataContainer> parent, final Class<?> child) {
175 String methodName = "get" + child.getSimpleName();
177 return parent.getMethod(methodName);
178 } catch (NoSuchMethodException e) {
179 throw new IllegalArgumentException(e);
180 } catch (SecurityException e) {
181 throw new IllegalStateException(e);
187 @SuppressWarnings("rawtypes")
188 private static class ContainerReadingStrategy extends DataObjectReadingStrategy {
190 public ContainerReadingStrategy(final Class<? extends DataContainer> parent, final Class<? extends DataContainer> child) {
191 super(parent, child);
192 checkArgument(child.isAssignableFrom(getGetterMethod().getReturnType()));
196 public Map<InstanceIdentifier, DataContainer> readUsingPathArgument(final DataContainer parent,
197 final PathArgument childArgument, final InstanceIdentifier parentPath) {
198 final DataContainer result = read(parent, childArgument.getType());
199 if (result != null) {
200 @SuppressWarnings("unchecked")
201 InstanceIdentifier childPath = parentPath.child(childArgument.getType());
202 return Collections.singletonMap(childPath, result);
204 return Collections.emptyMap();
208 public DataContainer read(final DataContainer parent, final Class<?> childType) {
210 Object potentialData = getGetterMethod().invoke(parent);
211 checkState(potentialData instanceof DataContainer);
212 return (DataContainer) potentialData;
214 } catch (IllegalAccessException | InvocationTargetException e) {
215 throw new IllegalArgumentException(e);
220 @SuppressWarnings("rawtypes")
221 private static class ListItemReadingStrategy extends DataObjectReadingStrategy {
223 public ListItemReadingStrategy(final Class<? extends DataContainer> parent, final Class child) {
224 super(parent, child);
225 checkArgument(Iterable.class.isAssignableFrom(getGetterMethod().getReturnType()));
229 public DataContainer read(final DataContainer parent, final Class<?> childType) {
230 // This will always fail since we do not have key.
234 @SuppressWarnings("unchecked")
236 public Map<InstanceIdentifier, DataContainer> readUsingPathArgument(final DataContainer parent,
237 final PathArgument childArgument, final InstanceIdentifier builder) {
239 Object potentialList = getGetterMethod().invoke(parent);
240 if (potentialList instanceof Iterable) {
242 final Iterable<Identifiable> dataList = (Iterable<Identifiable>) potentialList;
243 if (childArgument instanceof IdentifiableItem<?, ?>) {
244 return readUsingIdentifiableItem(dataList, (IdentifiableItem) childArgument, builder);
246 return readAll(dataList, builder);
249 } catch (InvocationTargetException | IllegalArgumentException | IllegalAccessException e) {
250 throw new IllegalStateException(e);
252 return Collections.emptyMap();
255 private Map<InstanceIdentifier, DataContainer> readAll(final Iterable<Identifiable> dataList,
256 final InstanceIdentifier parentPath) {
257 Builder<InstanceIdentifier, DataContainer> result = ImmutableMap
258 .<InstanceIdentifier, DataContainer> builder();
259 for (Identifiable item : dataList) {
260 @SuppressWarnings("unchecked")
261 InstanceIdentifier childPath = parentPath.child(getChildType(), item.getKey());
262 result.put(childPath, (DataContainer) item);
264 return result.build();
267 @SuppressWarnings("unchecked")
268 private static Map<InstanceIdentifier, DataContainer> readUsingIdentifiableItem(final Iterable<Identifiable> dataList,
269 final IdentifiableItem childArgument, final InstanceIdentifier parentPath) {
270 final Identifier<?> key = childArgument.getKey();
271 for (Identifiable item : dataList) {
272 if (key.equals(item.getKey()) && item instanceof DataContainer) {
273 checkState(childArgument.getType().isInstance(item),
274 "Found child is not instance of requested type");
275 InstanceIdentifier childPath = parentPath
276 .child(childArgument.getType(), item.getKey());
277 return Collections.singletonMap(childPath, (DataContainer) item);
280 return Collections.emptyMap();
285 private static final class AugmentationReadingStrategy extends DataObjectReadingStrategy {
287 public AugmentationReadingStrategy() {
288 super(Augmentable.class, Augmentation.class, null);
291 @SuppressWarnings("rawtypes")
293 public Map<InstanceIdentifier, DataContainer> readUsingPathArgument(final DataContainer parent,
294 final PathArgument childArgument, final InstanceIdentifier builder) {
295 checkArgument(childArgument instanceof Item<?>, "Path Argument must be Item without keys");
296 DataContainer aug = read(parent, childArgument.getType());
298 @SuppressWarnings("unchecked")
299 final InstanceIdentifier childPath = builder.child(childArgument.getType());
300 return Collections.singletonMap(childPath, aug);
302 return Collections.emptyMap();
307 public DataContainer read(final DataContainer parent, final Class<?> childType) {
308 checkArgument(Augmentation.class.isAssignableFrom(childType), "Parent must be Augmentable.");
309 checkArgument(parent instanceof Augmentable<?>, "Parent must be Augmentable.");
311 @SuppressWarnings({ "rawtypes", "unchecked" })
312 Augmentation potential = ((Augmentable) parent).getAugmentation(childType);
313 checkState(potential instanceof DataContainer, "Readed augmention must be data object");
314 return (DataContainer) potential;
319 * Create sublist view of child from element on [size-of-parent] position to
324 * @return sublist view of child argument
325 * @throws IllegalArgumentException
326 * if parent argument is bigger than child
328 private static <P, C> List<C> subList(final Iterable<P> parent, final Iterable<C> child) {
329 Iterator<P> iParent = parent.iterator();
330 List<C> result = new ArrayList<>();
331 for (C arg : child) {
332 if (iParent.hasNext()) {
338 if (iParent.hasNext()) {
339 throw new IllegalArgumentException("Parent argument is bigger than child.");