2 * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.openflowplugin.extension.api;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import java.util.HashSet;
15 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.yangtools.concepts.Immutable;
19 import org.opendaylight.yangtools.yang.binding.Augmentable;
20 import org.opendaylight.yangtools.yang.binding.Augmentation;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
24 * Resolver providing a bridge between a grouping and its various instantiations via augment. This is useful for
25 * extracting the grouping's content from a DataObject's augmentations without knowing from which instantiation it
29 * Typical use case is, given a base grouping module:
34 * container augmentable {
39 * and a module independent of it:
55 * an external module can perform:
59 * import bar { prefix bar; }
60 * import baz { prefix baz; }
62 * grouping something {
66 * augment /bar:bar/bar:augmentable {
70 * augment /baz:baz/baz:augmentable {
74 * The augmentations of {@code bar} and {@code baz} instantiations of {@code grouping foo} have an equivalent
75 * augmentation introduced by {@code xyzzy}. This equivalence is not expressed is generated code, in that it is
76 * not apparent given {@code bar} or {@code baz} there is an augmentation which provides {@code something}.
79 * This class provides the static knowledge to ask for the contents of {@code something} given an instance of
80 * {@code augmentable}, without knowing which augmentation introduces it.
82 * @param <G> Grouping type
83 * @param <T> Augmentable type
86 public final class AugmentationGroupingResolver<G extends DataObject, T extends Augmentable<T>> implements Immutable {
87 private final Class<? extends Augmentation<T>>[] augmentations;
88 private final Class<G> grouping;
90 AugmentationGroupingResolver(final Class<G> grouping, final Class<? extends Augmentation<T>>[] augmentations) {
91 this.grouping = requireNonNull(grouping);
92 this.augmentations = requireNonNull(augmentations);
95 public @NonNull Optional<G> findExtension(final T data) {
98 for (Class<? extends Augmentation<T>> cls : augmentations) {
99 final Augmentation<T> potential = data.augmentation(cls);
100 if (potential != null) {
101 return Optional.of(grouping.cast(potential));
104 return Optional.empty();
107 public static <G extends DataObject, T extends Augmentable<T>> @NonNull Builder<G, T> builder(
108 final Class<G> groupingClass) {
109 return new Builder<>(groupingClass);
112 @SuppressWarnings("unchecked")
113 public static <T extends Augmentable<T>> @NonNull Factory<T> factory(final Class<T> augmentableClass,
114 final Set<Class<? extends Augmentation<T>>> augmentationClasses) {
115 // Defensive copy via .clone() to guard against evil Set implementations
116 final Class<?>[] array = augmentationClasses.toArray(new Class<?>[0]).clone();
118 // Defensive check of all array elements
119 for (Class<?> clazz : array) {
120 checkArgument(Augmentation.class.isAssignableFrom(clazz), "Class %s is not an Augmentation", clazz);
123 return new Factory<>((Class<? extends Augmentation<T>>[]) array);
126 public static final class Builder<G extends DataObject, T extends Augmentable<T>> {
127 private final Set<Class<? extends Augmentation<T>>> augmentations = new HashSet<>();
128 private final Class<G> grouping;
130 Builder(final Class<G> groupingClass) {
131 grouping = requireNonNull(groupingClass);
134 public <X extends Augmentation<T>> @NonNull Builder<G, T> addAugmentationClass(
135 final Class<X> augmentationClass) {
136 checkAssignable(grouping, augmentationClass);
137 augmentations.add(augmentationClass);
141 @SuppressWarnings("unchecked")
142 public @NonNull AugmentationGroupingResolver<G, T> build() {
143 return new AugmentationGroupingResolver<>(grouping,
144 (Class<? extends Augmentation<T>>[]) augmentations.toArray(new Class<?>[0]));
148 public static final class Factory<T extends Augmentable<T>> implements Immutable {
149 private final Class<? extends Augmentation<T>>[] augmentations;
151 Factory(final Class<? extends Augmentation<T>>[] augmentations) {
152 this.augmentations = requireNonNull(augmentations);
155 public <G extends DataObject> @NonNull AugmentationGroupingResolver<G, T> createResolver(
156 final Class<G> groupingClass) {
157 for (Class<? extends Augmentation<T>> cls : augmentations) {
158 checkAssignable(groupingClass, cls);
161 return new AugmentationGroupingResolver<>(groupingClass, augmentations);
165 static void checkAssignable(final Class<?> groupingClass, final Class<?> augmentationClass) {
166 checkArgument(groupingClass.isAssignableFrom(augmentationClass), "%s is not compatible with grouping %s",
167 augmentationClass, groupingClass);