1 package org.opendaylight.yangtools.yang.binding.util;
3 import static com.google.common.base.Preconditions.checkArgument;
4 import static com.google.common.base.Preconditions.checkState;
6 import com.google.common.base.Optional;
7 import com.google.common.collect.ImmutableMap;
8 import com.google.common.collect.ImmutableMap.Builder;
9 import java.lang.reflect.InvocationTargetException;
10 import java.lang.reflect.Method;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Iterator;
14 import java.util.List;
16 import java.util.Map.Entry;
17 import org.opendaylight.yangtools.yang.binding.Augmentable;
18 import org.opendaylight.yangtools.yang.binding.Augmentation;
19 import org.opendaylight.yangtools.yang.binding.DataContainer;
20 import org.opendaylight.yangtools.yang.binding.DataObject;
21 import org.opendaylight.yangtools.yang.binding.Identifiable;
22 import org.opendaylight.yangtools.yang.binding.Identifier;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
28 public class DataObjectReadingUtil {
30 private DataObjectReadingUtil() {
31 throw new UnsupportedOperationException("Utility class. Instantion is not allowed.");
37 * Parent object on which read operation will be performed
39 * Path, to parent object.
41 * Path, which is nested to parent, and should be readed.
42 * @return Value of object.
44 public static final <T extends DataObject, P extends DataObject> Map<InstanceIdentifier<T>, T> readData(P parent,
45 InstanceIdentifier<P> parentPath, InstanceIdentifier<T> childPath) {
46 checkArgument(parent != null, "Parent must not be null.");
47 checkArgument(parentPath != null, "Parent path must not be null");
48 checkArgument(childPath != null, "Child path must not be null");
49 checkArgument(parentPath.containsWildcarded(childPath), "Parent object must be parent of child.");
51 List<PathArgument> pathArgs = subList(parentPath.getPathArguments(), childPath.getPathArguments());
52 @SuppressWarnings("rawtypes")
53 Map<InstanceIdentifier, DataContainer> lastFound = Collections
54 .<InstanceIdentifier, DataContainer> singletonMap(parentPath, parent);
55 for (PathArgument pathArgument : pathArgs) {
56 @SuppressWarnings("rawtypes")
57 final ImmutableMap.Builder<InstanceIdentifier, DataContainer> potentialBuilder = ImmutableMap.builder();
58 for (@SuppressWarnings("rawtypes")
59 Entry<InstanceIdentifier, DataContainer> entry : lastFound.entrySet()) {
60 potentialBuilder.putAll(readData(entry, pathArgument));
62 lastFound = potentialBuilder.build();
63 if (lastFound.isEmpty()) {
64 return Collections.emptyMap();
67 @SuppressWarnings({ "unchecked", "rawtypes" })
68 final Map<InstanceIdentifier<T>, T> result = (Map) lastFound;
72 @SuppressWarnings("rawtypes")
73 private static Map<InstanceIdentifier, DataContainer> readData(Entry<InstanceIdentifier, DataContainer> entry,
74 PathArgument pathArgument) {
75 return readData(entry.getValue(), entry.getKey(), pathArgument);
78 public static final <T extends DataObject> Optional<T> readData(DataObject source, Class<T> child) {
79 checkArgument(source != null, "Object should not be null.");
80 checkArgument(child != null, "Child type should not be null");
81 Class<? extends DataContainer> parentClass = source.getImplementedInterface();
83 @SuppressWarnings("unchecked")
84 T potential = (T) resolveReadStrategy(parentClass, child).read(source, child);
85 return Optional.fromNullable(potential);
88 @SuppressWarnings("rawtypes")
89 private static final Map<InstanceIdentifier, DataContainer> readData(DataContainer parent,
90 InstanceIdentifier parentPath, PathArgument child) {
91 checkArgument(parent != null, "Object should not be null.");
92 checkArgument(child != null, "Child argument should not be null");
93 Class<? extends DataContainer> parentClass = parent.getImplementedInterface();
94 return resolveReadStrategy(parentClass, child.getType()).readUsingPathArgument(parent, child, parentPath);
97 private static DataObjectReadingStrategy resolveReadStrategy(Class<? extends DataContainer> parentClass,
98 Class<? extends DataContainer> type) {
100 DataObjectReadingStrategy strategy = createReadStrategy(parentClass, type);
101 // FIXME: Add caching of strategies
105 private static DataObjectReadingStrategy createReadStrategy(Class<? extends DataContainer> parent,
106 Class<? extends DataContainer> child) {
108 if (Augmentable.class.isAssignableFrom(parent) && Augmentation.class.isAssignableFrom(child)) {
109 return REAUSABLE_AUGMENTATION_READING_STRATEGY;
113 * FIXME Ensure that this strategies also works for children of cases.
114 * Possible edge-case is : Parent container uses grouping foo case is
115 * added by augmentation also uses foo.
117 if (Identifiable.class.isAssignableFrom(child)) {
118 @SuppressWarnings("unchecked")
119 final Class<? extends Identifiable<?>> identifiableClass = (Class<? extends Identifiable<?>>) child;
120 return new ListItemReadingStrategy(parent, identifiableClass);
122 return new ContainerReadingStrategy(parent, child);
125 private static Method resolveGetterMethod(Class<? extends DataContainer> parent, Class<?> child) {
126 String methodName = "get" + child.getSimpleName();
128 return parent.getMethod(methodName);
129 } catch (NoSuchMethodException e) {
130 throw new IllegalArgumentException(e);
131 } catch (SecurityException e) {
132 throw new IllegalStateException(e);
136 @SuppressWarnings("rawtypes")
137 private static abstract class DataObjectReadingStrategy {
139 private final Class<? extends DataContainer> parentType;
140 private final Class<? extends DataContainer> childType;
141 private final Method getterMethod;
143 @SuppressWarnings("unchecked")
144 public DataObjectReadingStrategy(Class parentType, Class childType) {
146 checkArgument(DataContainer.class.isAssignableFrom(parentType));
147 checkArgument(DataContainer.class.isAssignableFrom(childType));
148 this.parentType = parentType;
149 this.childType = childType;
150 this.getterMethod = resolveGetterMethod(parentType, childType);
153 @SuppressWarnings("unchecked")
154 public DataObjectReadingStrategy(Class parentType, Class childType, Method getter) {
155 this.parentType = parentType;
156 this.childType = childType;
157 this.getterMethod = getter;
160 @SuppressWarnings("unused")
161 protected Class<? extends DataContainer> getParentType() {
165 protected Class<? extends DataContainer> getChildType() {
169 protected Method getGetterMethod() {
173 abstract public Map<InstanceIdentifier, DataContainer> readUsingPathArgument(DataContainer parent,
174 PathArgument childArgument, InstanceIdentifier targetBuilder);
176 abstract public DataContainer read(DataContainer parent, Class<?> childType);
180 @SuppressWarnings("rawtypes")
181 private static class ContainerReadingStrategy extends DataObjectReadingStrategy {
183 public ContainerReadingStrategy(Class<? extends DataContainer> parent, Class<? extends DataContainer> child) {
184 super(parent, child);
185 checkArgument(child.isAssignableFrom(getGetterMethod().getReturnType()));
189 public Map<InstanceIdentifier, DataContainer> readUsingPathArgument(DataContainer parent,
190 PathArgument childArgument, InstanceIdentifier parentPath) {
191 final DataContainer result = read(parent, childArgument.getType());
192 if (result != null) {
193 @SuppressWarnings("unchecked")
194 InstanceIdentifier childPath = parentPath.child(childArgument.getType());
195 return Collections.singletonMap(childPath, result);
197 return Collections.emptyMap();
201 public DataContainer read(DataContainer parent, Class<?> childType) {
203 Object potentialData = getGetterMethod().invoke(parent);
204 checkState(potentialData instanceof DataContainer);
205 return (DataContainer) potentialData;
207 } catch (IllegalAccessException | InvocationTargetException e) {
208 throw new IllegalArgumentException(e);
213 @SuppressWarnings("rawtypes")
214 private static class ListItemReadingStrategy extends DataObjectReadingStrategy {
216 public ListItemReadingStrategy(Class<? extends DataContainer> parent, Class child) {
217 super(parent, child);
218 checkArgument(Iterable.class.isAssignableFrom(getGetterMethod().getReturnType()));
222 public DataContainer read(DataContainer parent, Class<?> childType) {
223 // This will always fail since we do not have key.
227 @SuppressWarnings("unchecked")
229 public Map<InstanceIdentifier, DataContainer> readUsingPathArgument(DataContainer parent,
230 PathArgument childArgument, InstanceIdentifier builder) {
232 Object potentialList = getGetterMethod().invoke(parent);
233 if (potentialList instanceof Iterable) {
235 final Iterable<Identifiable> dataList = (Iterable<Identifiable>) potentialList;
236 if (childArgument instanceof IdentifiableItem<?, ?>) {
237 return readUsingIdentifiableItem(dataList, (IdentifiableItem) childArgument, builder);
239 return readAll(dataList, builder);
242 } catch (InvocationTargetException e) {
243 throw new IllegalStateException(e);
244 } catch (IllegalAccessException e) {
245 throw new IllegalStateException(e);
246 } catch (IllegalArgumentException e) {
247 throw new IllegalStateException(e);
249 return Collections.emptyMap();
252 private Map<InstanceIdentifier, DataContainer> readAll(Iterable<Identifiable> dataList,
253 InstanceIdentifier parentPath) {
254 Builder<InstanceIdentifier, DataContainer> result = ImmutableMap
255 .<InstanceIdentifier, DataContainer> builder();
256 for (Identifiable item : dataList) {
257 @SuppressWarnings("unchecked")
258 InstanceIdentifier childPath = parentPath.child(getChildType(), item.getKey());
259 result.put(childPath, (DataContainer) item);
261 return result.build();
264 @SuppressWarnings("unchecked")
265 private Map<InstanceIdentifier, DataContainer> readUsingIdentifiableItem(Iterable<Identifiable> dataList,
266 IdentifiableItem childArgument, InstanceIdentifier parentPath) {
267 final Identifier<?> key = childArgument.getKey();
268 for (Identifiable item : dataList) {
269 if (key.equals(item.getKey()) && item instanceof DataContainer) {
270 checkState(childArgument.getType().isInstance(item),
271 "Found child is not instance of requested type");
272 InstanceIdentifier childPath = parentPath
273 .child(childArgument.getType(), item.getKey());
274 return Collections.singletonMap(childPath, (DataContainer) item);
277 return Collections.emptyMap();
282 private static final DataObjectReadingStrategy REAUSABLE_AUGMENTATION_READING_STRATEGY = new AugmentationReadingStrategy();
284 private static final class AugmentationReadingStrategy extends DataObjectReadingStrategy {
286 public AugmentationReadingStrategy() {
287 super(Augmentable.class, Augmentation.class, null);
290 @SuppressWarnings("rawtypes")
292 public Map<InstanceIdentifier, DataContainer> readUsingPathArgument(DataContainer parent,
293 PathArgument childArgument, InstanceIdentifier builder) {
294 checkArgument(childArgument instanceof Item<?>, "Path Argument must be Item without keys");
295 DataContainer aug = read(parent, childArgument.getType());
297 @SuppressWarnings("unchecked")
298 final InstanceIdentifier childPath = builder.child(childArgument.getType());
299 return Collections.singletonMap(childPath, aug);
301 return Collections.emptyMap();
306 public DataContainer read(DataContainer parent, Class<?> childType) {
307 checkArgument(Augmentation.class.isAssignableFrom(childType), "Parent must be Augmentable.");
308 checkArgument(parent instanceof Augmentable<?>, "Parent must be Augmentable.");
310 @SuppressWarnings({ "rawtypes", "unchecked" })
311 Augmentation potential = ((Augmentable) parent).getAugmentation(childType);
312 checkState(potential instanceof DataContainer, "Readed augmention must be data object");
313 return (DataContainer) potential;
318 * Create sublist view of child from element on [size-of-parent] position to
323 * @return sublist view of child argument
324 * @throws IllegalArgumentException
325 * if parent argument is bigger than child
327 private static <P, C> List<C> subList(Iterable<P> parent, Iterable<C> child) {
328 Iterator<P> iParent = parent.iterator();
329 List<C> result = new ArrayList<>();
330 for (C arg : child) {
331 if (iParent.hasNext()) {
337 if (iParent.hasNext()) {
338 throw new IllegalArgumentException("Parent argument is bigger than child.");