5dfe8206cb0647c2b1d34cc8cea0aecde3ff8e58
[mdsal.git] / binding / mdsal-binding-generator-util / src / main / java / org / opendaylight / mdsal / binding / model / util / Types.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. 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.mdsal.binding.model.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.Preconditions;
13 import com.google.common.cache.CacheBuilder;
14 import com.google.common.cache.CacheLoader;
15 import com.google.common.cache.LoadingCache;
16 import com.google.common.collect.ImmutableRangeSet;
17 import com.google.common.collect.Range;
18 import com.google.common.collect.RangeSet;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import java.io.Serializable;
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Objects;
26 import java.util.Optional;
27 import java.util.Set;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.opendaylight.mdsal.binding.model.api.BaseTypeWithRestrictions;
30 import org.opendaylight.mdsal.binding.model.api.ConcreteType;
31 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
32 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
33 import org.opendaylight.mdsal.binding.model.api.Restrictions;
34 import org.opendaylight.mdsal.binding.model.api.Type;
35 import org.opendaylight.mdsal.binding.model.api.WildcardType;
36 import org.opendaylight.yangtools.yang.binding.Augmentable;
37 import org.opendaylight.yangtools.yang.binding.Augmentation;
38 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
39 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
40 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
41
42 public final class Types {
43     private static final CacheLoader<Class<?>, ConcreteType> TYPE_LOADER = new CacheLoader<Class<?>, ConcreteType>() {
44         @Override
45         public ConcreteType load(final Class<?> key) {
46             return new ConcreteTypeImpl(JavaTypeName.create(key), null);
47         }
48     };
49     private static final LoadingCache<Class<?>, ConcreteType> TYPE_CACHE =
50             CacheBuilder.newBuilder().weakKeys().build(TYPE_LOADER);
51
52
53     public static final ConcreteType BOOLEAN = typeForClass(Boolean.class);
54     public static final ConcreteType STRING = typeForClass(String.class);
55     public static final ConcreteType VOID = typeForClass(Void.class);
56     public static final ConcreteType BYTE_ARRAY = typeForClass(byte[].class);
57
58     private static final ConcreteType CLASS = typeForClass(Class.class);
59     private static final ConcreteType LIST_TYPE = typeForClass(List.class);
60     private static final ConcreteType LISTENABLE_FUTURE = typeForClass(ListenableFuture.class);
61     private static final ConcreteType MAP_TYPE = typeForClass(Map.class);
62     private static final ConcreteType OBJECT = typeForClass(Object.class);
63     private static final ConcreteType PRIMITIVE_VOID = typeForClass(void.class);
64     private static final ConcreteType SERIALIZABLE = typeForClass(Serializable.class);
65     private static final ConcreteType SET_TYPE = typeForClass(Set.class);
66
67     /**
68      * It is not desirable to create instance of this class
69      */
70     private Types() {
71     }
72
73     /**
74      * Returns an instance of {@link ParameterizedType} which represents JAVA <code>java.lang.Class</code> type
75      * specialized to specified type.
76      *
77      * @param type Type for which to specialize
78      * @return A parameterized type corresponding to {@code Class<Type>}
79      * @throws NullPointerException if {@code type} is null
80      */
81     public static ParameterizedType classType(final Type type) {
82         return parameterizedTypeFor(CLASS, type);
83     }
84
85     /**
86      * Returns an instance of {@link ConcreteType} which represents JAVA <code>java.lang.Void</code> type.
87      *
88      * @return <code>ConcreteType</code> instance which represents JAVA <code>java.lang.Void</code>
89      */
90     public static ConcreteType voidType() {
91         return VOID;
92     }
93
94     /**
95      * Returns an instance of {@link ConcreteType} which represents {@link Object} type.
96      *
97      * @return <code>ConcreteType</code> instance which represents {@link Object}
98      */
99     public static ConcreteType objectType() {
100         return OBJECT;
101     }
102
103     /**
104      * Returns an instance of {@link ConcreteType} which represents JAVA <code>void</code> type.
105      *
106      * @return <code>ConcreteType</code> instance which represents JAVA <code>void</code>
107      */
108     public static ConcreteType primitiveVoidType() {
109         return PRIMITIVE_VOID;
110     }
111
112     /**
113      * Returns an instance of {@link ConcreteType} which represents {@link Serializable} type.
114      *
115      * @return <code>ConcreteType</code> instance which represents JAVA <code>{@link Serializable}</code>
116      */
117     public static ConcreteType serializableType() {
118         return SERIALIZABLE;
119     }
120
121     /**
122      * Returns an instance of {@link ConcreteType} describing the class
123      *
124      * @param cls
125      *            Class to describe
126      * @return Description of class
127      */
128     public static ConcreteType typeForClass(final Class<?> cls) {
129         return TYPE_CACHE.getUnchecked(cls);
130     }
131
132     public static ConcreteType typeForClass(final Class<?> cls, final Restrictions restrictions) {
133         if (restrictions == null) {
134             return typeForClass(cls);
135         }
136
137         final JavaTypeName identifier = JavaTypeName.create(cls);
138         if (restrictions instanceof DefaultRestrictions) {
139             return new ConcreteTypeImpl(identifier, restrictions);
140         }
141         return new BaseTypeWithRestrictionsImpl(identifier, restrictions);
142     }
143
144     /**
145      * Returns an instance of {@link ParameterizedType} describing the typed
146      * {@link Map}&lt;K,V&gt;
147      *
148      * @param keyType
149      *            Key Type
150      * @param valueType
151      *            Value Type
152      * @return Description of generic type instance
153      */
154     public static ParameterizedType mapTypeFor(final Type keyType, final Type valueType) {
155         return parameterizedTypeFor(MAP_TYPE, keyType, valueType);
156     }
157
158     /**
159      * Returns an instance of {@link ParameterizedType} describing the typed
160      * {@link Set}&lt;V&gt; with concrete type of value.
161      *
162      * @param valueType
163      *            Value Type
164      * @return Description of generic type instance of Set
165      */
166     public static ParameterizedType setTypeFor(final Type valueType) {
167         return parameterizedTypeFor(SET_TYPE, valueType);
168     }
169
170     /**
171      * Returns an instance of {@link ParameterizedType} describing the typed
172      * {@link List}&lt;V&gt; with concrete type of value.
173      *
174      * @param valueType
175      *            Value Type
176      * @return Description of type instance of List
177      */
178     public static ParameterizedType listTypeFor(final Type valueType) {
179         return parameterizedTypeFor(LIST_TYPE, valueType);
180     }
181
182     public static boolean isListType(final Type type) {
183         return type instanceof ParameterizedType && LIST_TYPE.equals(((ParameterizedType) type).getRawType());
184     }
185
186     /**
187      * Returns an instance of {@link ParameterizedType} describing the typed
188      * {@link ListenableFuture}&lt;V&gt; with concrete type of value.
189      *
190      * @param valueType
191      *            Value Type
192      * @return Description of type instance of ListenableFuture
193      */
194     public static ParameterizedType listenableFutureTypeFor(final Type valueType) {
195         return parameterizedTypeFor(LISTENABLE_FUTURE, valueType);
196     }
197
198     /**
199      * Creates instance of type
200      * {@link org.opendaylight.mdsal.binding.model.api.ParameterizedType
201      * ParameterizedType}
202      *
203      * @param type
204      *            JAVA <code>Type</code> for raw type
205      * @param parameters
206      *            JAVA <code>Type</code>s for actual parameter types
207      * @return <code>ParametrizedType</code> representation of <code>type</code>
208      *         and its parameters <code>parameters</code>
209      * @throws NullPointerException if any argument or any member of {@code parameters} is null
210      */
211     public static ParameterizedType parameterizedTypeFor(final Type type, final Type... parameters) {
212         return new ParametrizedTypeImpl(type, parameters);
213     }
214
215     /**
216      * Creates instance of type {@link org.opendaylight.mdsal.binding.model.api.WildcardType}.
217      *
218      * @param identifier JavaTypeName of the type
219      * @return <code>WildcardType</code> representation of specified identifier
220      */
221     public static WildcardType wildcardTypeFor(final JavaTypeName identifier) {
222         return new WildcardTypeImpl(identifier);
223     }
224
225     /**
226      * Creates instance of
227      * {@link org.opendaylight.mdsal.binding.model.api.ParameterizedType
228      * ParameterizedType} where raw type is
229      * {@link org.opendaylight.yangtools.yang.binding.Augmentable} and actual
230      * parameter is <code>valueType</code>.
231      *
232      * @param valueType
233      *            JAVA <code>Type</code> with actual parameter
234      * @return <code>ParametrizedType</code> representation of raw type
235      *         <code>Augmentable</code> with actual parameter
236      *         <code>valueType</code>
237      */
238     public static ParameterizedType augmentableTypeFor(final Type valueType) {
239         final Type augmentable = typeForClass(Augmentable.class);
240         return parameterizedTypeFor(augmentable, valueType);
241     }
242
243     /**
244      * Creates instance of
245      * {@link org.opendaylight.mdsal.binding.model.api.ParameterizedType
246      * ParameterizedType} where raw type is
247      * {@link org.opendaylight.yangtools.yang.binding.Augmentation} and actual
248      * parameter is <code>valueType</code>.
249      *
250      * @param valueType
251      *            JAVA <code>Type</code> with actual parameter
252      * @return <code>ParametrizedType</code> reprezentation of raw type
253      *         <code>Augmentation</code> with actual parameter
254      *         <code>valueType</code>
255      */
256     public static ParameterizedType augmentationTypeFor(final Type valueType) {
257         final Type augmentation = typeForClass(Augmentation.class);
258         return parameterizedTypeFor(augmentation, valueType);
259     }
260
261     public static @Nullable String getOuterClassName(final Type valueType) {
262         return valueType.getIdentifier().immediatelyEnclosingClass().map(Object::toString).orElse(null);
263     }
264
265     /**
266      *
267      * Represents concrete JAVA type.
268      *
269      */
270     private static final class ConcreteTypeImpl extends AbstractBaseType implements ConcreteType {
271         private final Restrictions restrictions;
272
273         /**
274          * Creates instance of this class with package <code>pkName</code> and
275          * with the type name <code>name</code>.
276          *
277          * @param pkName
278          *            string with package name
279          * @param name
280          *            string with the name of the type
281          */
282         ConcreteTypeImpl(final JavaTypeName identifier, final Restrictions restrictions) {
283             super(identifier);
284             this.restrictions = restrictions;
285         }
286
287         @Override
288         public Restrictions getRestrictions() {
289             return this.restrictions;
290         }
291     }
292
293     /**
294      * Represents concrete JAVA type with changed restriction values.
295      */
296     private static final class BaseTypeWithRestrictionsImpl extends AbstractBaseType implements BaseTypeWithRestrictions {
297         private final Restrictions restrictions;
298
299         /**
300          * Creates instance of this class with package <code>pkName</code> and
301          * with the type name <code>name</code>.
302          *
303          * @param pkName
304          *            string with package name
305          * @param name
306          *            string with the name of the type
307          */
308         BaseTypeWithRestrictionsImpl(final JavaTypeName identifier, final Restrictions restrictions) {
309             super(identifier);
310             this.restrictions = Preconditions.checkNotNull(restrictions);
311         }
312
313         @Override
314         public Restrictions getRestrictions() {
315             return this.restrictions;
316         }
317     }
318
319     /**
320      * Represents parametrized JAVA type.
321      */
322     private static class ParametrizedTypeImpl extends AbstractBaseType implements ParameterizedType {
323         /**
324          * Array of JAVA actual type parameters.
325          */
326         private final Type[] actualTypes;
327
328         /**
329          * JAVA raw type (like List, Set, Map...)
330          */
331         private final Type rawType;
332
333         @Override
334         public Type[] getActualTypeArguments() {
335
336             return this.actualTypes;
337         }
338
339         @Override
340         public Type getRawType() {
341             return this.rawType;
342         }
343
344         /**
345          * Creates instance of this class with concrete rawType and array of
346          * actual parameters.
347          *
348          * @param rawType
349          *            JAVA <code>Type</code> for raw type
350          * @param actTypes
351          *            array of actual parameters
352          */
353         public ParametrizedTypeImpl(final Type rawType, final Type[] actTypes) {
354             super(rawType.getIdentifier());
355             this.rawType = requireNonNull(rawType);
356             actualTypes = actTypes.clone();
357             if (Arrays.stream(actualTypes).anyMatch(Objects::isNull)) {
358                 throw new NullPointerException("actTypes contains a null");
359             }
360         }
361     }
362
363     /**
364      * Represents JAVA bounded wildcard type.
365      */
366     private static class WildcardTypeImpl extends AbstractBaseType implements WildcardType {
367         /**
368          * Creates instance of this class with concrete package and type name.
369          *
370          * @param packageName
371          *            string with the package name
372          * @param typeName
373          *            string with the name of type
374          */
375         WildcardTypeImpl(final JavaTypeName identifier) {
376             super(identifier);
377         }
378     }
379
380     public static <T extends Number& Comparable<T>> DefaultRestrictions<T> getDefaultRestrictions(final T min,
381             final T max) {
382         return new DefaultRestrictions<>(min, max);
383     }
384
385     private static final class DefaultRestrictions<T extends Number & Comparable<T>> implements Restrictions {
386         private final T min;
387         private final T max;
388         private final RangeConstraint<?> rangeConstraint;
389
390         private DefaultRestrictions(final T min, final T max) {
391             this.min = Preconditions.checkNotNull(min);
392             this.max = Preconditions.checkNotNull(max);
393
394             this.rangeConstraint = new RangeConstraint<T>() {
395
396                 @Override
397                 public Optional<String> getErrorAppTag() {
398                     return Optional.empty();
399                 }
400
401                 @Override
402                 public Optional<String> getErrorMessage() {
403                     return Optional.empty();
404                 }
405
406                 @Override
407                 public Optional<String> getDescription() {
408                     return Optional.empty();
409                 }
410
411                 @Override
412                 public Optional<String> getReference() {
413                     return Optional.empty();
414                 }
415
416                 @Override
417                 public RangeSet<T> getAllowedRanges() {
418                     return ImmutableRangeSet.of(Range.closed(min, max));
419                 }
420             };
421         }
422
423         @Override
424         public boolean isEmpty() {
425             return false;
426         }
427
428         @Override
429         public Optional<? extends RangeConstraint<?>> getRangeConstraint() {
430             return Optional.of(rangeConstraint);
431         }
432
433         @Override
434         public List<PatternConstraint> getPatternConstraints() {
435             return Collections.emptyList();
436         }
437
438         @Override
439         public Optional<LengthConstraint> getLengthConstraint() {
440             return Optional.empty();
441         }
442     }
443 }