Improve OffsetMapTemplate error reporting
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / SharedSingletonMapTemplate.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.util;
9
10 import com.google.common.base.MoreObjects;
11 import java.util.Map;
12 import java.util.function.BiFunction;
13 import org.eclipse.jdt.annotation.NonNull;
14
15 /**
16  * Template for instantiating {@link SharedSingletonMap} instances with a fixed key. The template can then be
17  * used as a factory for instances via using {@link #instantiateTransformed(Map, BiFunction)} or, more efficiently,
18  * using {@link #instantiateWithValue(Object)}.
19  *
20  * @param <K> the type of keys maintained by this template
21  */
22 public abstract sealed class SharedSingletonMapTemplate<K> extends ImmutableMapTemplate<K> {
23     private static final class Ordered<K> extends SharedSingletonMapTemplate<K> {
24         Ordered(final K key) {
25             super(key);
26         }
27
28         @Override
29         public <V> @NonNull SharedSingletonMap<K, V> instantiateWithValue(final V value) {
30             return new SharedSingletonMap.Ordered<>(keySet(), value);
31         }
32     }
33
34     private static final class Unordered<K> extends SharedSingletonMapTemplate<K> {
35         Unordered(final K key) {
36             super(key);
37         }
38
39         @Override
40         public <V> @NonNull SharedSingletonMap<K, V> instantiateWithValue(final V value) {
41             return new SharedSingletonMap.Unordered<>(keySet(), value);
42         }
43     }
44
45     private final @NonNull SingletonSet<K> keySet;
46
47     private SharedSingletonMapTemplate(final K key) {
48         keySet = SharedSingletonMap.cachedSet(key);
49     }
50
51     /**
52      * Create a template which produces Maps with specified key. The resulting map will retain insertion order through
53      * {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
54      *
55      * @param key Single key in resulting map
56      * @param <K> the type of keys maintained by resulting template
57      * @return A template object.
58      * @throws NullPointerException if {@code key} is null
59      */
60     public static <K> @NonNull SharedSingletonMapTemplate<K> ordered(final K key) {
61         return new Ordered<>(key);
62     }
63
64     /**
65      * Create a template which produces Maps with specified key. The resulting map will NOT retain ordering through
66      * {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
67      *
68      * @param key Single key in resulting map
69      * @param <K> the type of keys maintained by resulting template
70      * @return A template object.
71      * @throws NullPointerException if {@code key} is null
72      */
73     public static <K> @NonNull SharedSingletonMapTemplate<K> unordered(final K key) {
74         return new Unordered<>(key);
75     }
76
77     @Override
78     public final SingletonSet<K> keySet() {
79         return keySet;
80     }
81
82     @Override
83     public final <T, V> @NonNull SharedSingletonMap<K, V> instantiateTransformed(final Map<K, T> fromMap,
84             final BiFunction<K, T, V> valueTransformer) {
85         final var it = fromMap.entrySet().iterator();
86         if (!it.hasNext()) {
87             throw new IllegalArgumentException("Input is empty while expecting 1 item");
88         }
89
90         final var entry = it.next();
91         final var expected = keySet.getElement();
92         final var actual = entry.getKey();
93         if (!expected.equals(actual)) {
94             throw new IllegalArgumentException("Unexpected key " + actual + ", expecting " + expected);
95         }
96
97         final var value = transformValue(actual, entry.getValue(), valueTransformer);
98         if (it.hasNext()) {
99             throw new IllegalArgumentException("Input has more than one item");
100         }
101         return instantiateWithValue(value);
102     }
103
104     @Override
105     @SafeVarargs
106     public final <V> @NonNull SharedSingletonMap<K, V> instantiateWithValues(final V... values) {
107         checkSize(1, values.length);
108         return instantiateWithValue(values[0]);
109     }
110
111     /**
112      * Instantiate an immutable map with the value supplied.
113      *
114      * @param value Value to use
115      * @param <V> the type of mapped values
116      * @return An immutable map
117      * @throws NullPointerException if {@code value} is null
118      */
119     public abstract <V> @NonNull SharedSingletonMap<K, V> instantiateWithValue(V value);
120
121     @Override
122     public final String toString() {
123         return MoreObjects.toStringHelper(this).add("keySet", keySet).toString();
124     }
125 }