HONEYCOMB-448: JAVA 11 support
[honeycomb.git] / infra / translate-utils / src / main / java / io / fd / honeycomb / translate / util / RWUtils.java
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.translate.util;
18
19 import com.google.common.base.Function;
20 import com.google.common.base.Preconditions;
21 import com.google.common.collect.Iterables;
22 import com.google.common.collect.Maps;
23 import io.fd.honeycomb.translate.SubtreeManager;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.stream.Collector;
29 import java.util.stream.Collectors;
30 import java.util.stream.StreamSupport;
31 import javax.annotation.Nonnull;
32 import org.opendaylight.yangtools.yang.binding.Augmentation;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.opendaylight.yangtools.yang.binding.Identifiable;
35 import org.opendaylight.yangtools.yang.binding.Identifier;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37
38 public final class RWUtils {
39
40     // TODO(HONEYCOMB-172): update the utils methods considering Java8.
41     // Make sure they still work by wiring a detailed unit test first
42
43     public static final Function<SubtreeManager<? extends DataObject>, Class<? extends DataObject>>
44         MANAGER_CLASS_FUNCTION = input -> input.getManagedDataObjectType().getTargetType();
45
46     public static final Function<SubtreeManager<? extends Augmentation<?>>, Class<? extends DataObject>>
47         MANAGER_CLASS_AUG_FUNCTION = input -> {
48         final Class<? extends Augmentation<?>> targetType = input.getManagedDataObjectType().getTargetType();
49         Preconditions.checkArgument(DataObject.class.isAssignableFrom(targetType));
50         return (Class<? extends DataObject>) targetType;
51     };
52
53     private RWUtils() {}
54
55     /**
56      * Collector expecting only a single resulting item from a stream.
57      */
58     public static<T> Collector<T,?,T> singleItemCollector() {
59         return Collectors.collectingAndThen(
60                 Collectors.toList(),
61                 list -> {
62                     if (list.size() != 1) {
63                         throw new IllegalStateException("Unexpected size of list: " + list + ". Single item expected");
64                     }
65                     return list.get(0);
66                 }
67         );
68     }
69
70     /**
71      * Find next item in ID after provided type.
72      */
73     @Nonnull
74     public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier<? extends DataObject> id,
75                                                             @Nonnull final InstanceIdentifier<? extends DataObject> type) {
76         final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments();
77         final int i = Iterables.indexOf(pathArguments, input -> input.getType().isAssignableFrom(type.getTargetType()));
78         Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id);
79         return Iterables.get(pathArguments, i + 1);
80     }
81
82     /**
83      * Replace last item in ID with a provided IdentifiableItem of the same type.
84      */
85     @SuppressWarnings("unchecked")
86     @Nonnull
87     public static <D extends DataObject & Identifiable<K>, K extends Identifier<D>> InstanceIdentifier<D> replaceLastInId(
88         @Nonnull final InstanceIdentifier<D> id, final InstanceIdentifier.IdentifiableItem<D, K> currentBdItem) {
89
90         final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments();
91         final Iterable<InstanceIdentifier.PathArgument> withoutCurrent =
92             Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1);
93         final Iterable<InstanceIdentifier.PathArgument> concat =
94             Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem));
95         return (InstanceIdentifier<D>) InstanceIdentifier.create(concat);
96     }
97
98     /**
99      * Create IdentifiableItem from target type of provided ID with provided key.
100      */
101     @Nonnull
102     public static <D extends DataObject & Identifiable<K>, K extends Identifier<D>> InstanceIdentifier.IdentifiableItem<D, K> getCurrentIdItem(
103         @Nonnull final InstanceIdentifier<D> id, final K key) {
104         return InstanceIdentifier.IdentifiableItem.of(id.getTargetType(), key);
105     }
106
107     /**
108      * Trim InstanceIdentifier at indexOf(type).
109      */
110     @SuppressWarnings("unchecked")
111     @Nonnull
112     public static <D extends DataObject> InstanceIdentifier<D> cutId(@Nonnull final InstanceIdentifier<? extends DataObject> id,
113                                                                      @Nonnull final InstanceIdentifier<D> type) {
114         final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments();
115         final int i = Iterables.indexOf(pathArguments, input -> input.getType().equals(type.getTargetType()));
116         Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type);
117         return (InstanceIdentifier<D>) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1));
118     }
119
120     /**
121      * Trim InstanceIdentifier at indexOf(type).
122      */
123     @Nonnull
124     public static <D extends DataObject> InstanceIdentifier<D> cutId(@Nonnull final InstanceIdentifier<? extends DataObject> id,
125                                                                      @Nonnull final Class<D> type) {
126         return cutId(id, InstanceIdentifier.create(type));
127     }
128
129     /**
130      * Create an ordered map from a collection, checking for duplicity in the process.
131      */
132     @Nonnull
133     public static <K, V> Map<K, V> uniqueLinkedIndex(@Nonnull final Collection<V> values, @Nonnull final Function<? super V, K> keyFunction) {
134         final Map<K, V> objectObjectLinkedHashMap = Maps.newLinkedHashMap();
135         for (V value : values) {
136             final K key = keyFunction.apply(value);
137             Preconditions.checkArgument(objectObjectLinkedHashMap.put(key, value) == null,
138                 "Duplicate key detected : %s", key);
139         }
140         return objectObjectLinkedHashMap;
141     }
142
143     /**
144      * Transform a keyed instance identifier into a wildcarded one.
145      *
146      * ! This has to be called also for wildcarded List instance identifiers
147      * due to weird behavior of equals in InstanceIdentifier !
148      */
149     @SuppressWarnings("unchecked")
150     public static <D extends DataObject> InstanceIdentifier<D> makeIidWildcarded(final InstanceIdentifier<D> id) {
151         final List<InstanceIdentifier.PathArgument> transformedPathArguments =
152                 StreamSupport.stream(id.getPathArguments().spliterator(), false)
153                         .map(RWUtils::cleanPathArgumentFromKeys)
154                         .collect(Collectors.toList());
155         return (InstanceIdentifier<D>) InstanceIdentifier.create(transformedPathArguments);
156     }
157
158     /**
159      * Transform a keyed instance identifier into a wildcarded one, keeping keys except the last item.
160      */
161     @SuppressWarnings("unchecked")
162     public static <D extends DataObject> InstanceIdentifier<D> makeIidLastWildcarded(final InstanceIdentifier<D> id) {
163         final InstanceIdentifier.Item<D> wildcardedItem = InstanceIdentifier.Item.of(id.getTargetType());
164         final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments();
165         return (InstanceIdentifier<D>) InstanceIdentifier.create(
166                 Iterables.concat(
167                         Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1),
168                         Collections.singleton(wildcardedItem)));
169     }
170
171     private static InstanceIdentifier.PathArgument cleanPathArgumentFromKeys(final InstanceIdentifier.PathArgument pathArgument) {
172         return pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>
173                 ? InstanceIdentifier.Item.of(pathArgument.getType())
174                 : pathArgument;
175     }
176 }