40f8f7701365aa2c6ae0083f5302a6b94faace87
[mdsal.git] / binding2 / mdsal-binding2-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / javav2 / java / api / generator / rangeGenerators / AbstractRangeGenerator.java
1 /*
2  * Copyright (c) 2017 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.javav2.java.api.generator.rangeGenerators;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.collect.ImmutableMap.Builder;
13 import java.util.Map;
14 import javax.annotation.Nonnull;
15 import org.opendaylight.mdsal.binding.javav2.model.api.ConcreteType;
16 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
17 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 public abstract class AbstractRangeGenerator<T extends Number & Comparable<T>> {
22     private static final Logger LOG = LoggerFactory.getLogger(AbstractRangeGenerator.class);
23     private static final Map<String, AbstractRangeGenerator<?>> GENERATORS;
24
25     private static void addGenerator(final Builder<String, AbstractRangeGenerator<?>> b, final AbstractRangeGenerator<?> generator) {
26         b.put(generator.getTypeClass().getCanonicalName(), generator);
27     }
28
29     static {
30         final Builder<String, AbstractRangeGenerator<?>> b = ImmutableMap.builder();
31         addGenerator(b, new ByteRangeGenerator());
32         addGenerator(b, new ShortRangeGenerator());
33         addGenerator(b, new IntegerRangeGenerator());
34         addGenerator(b, new LongRangeGenerator());
35         addGenerator(b, new Uint8RangeGenerator());
36         addGenerator(b, new Uint16RangeGenerator());
37         addGenerator(b, new Uint32RangeGenerator());
38         addGenerator(b, new Uint64RangeGenerator());
39         addGenerator(b, new BigDecimalRangeGenerator());
40         addGenerator(b, new BigIntegerRangeGenerator());
41         GENERATORS = b.build();
42     }
43
44     private final Class<T> type;
45
46     protected AbstractRangeGenerator(final Class<T> typeClass) {
47         this.type = Preconditions.checkNotNull(typeClass);
48     }
49
50     public static AbstractRangeGenerator<?> forType(@Nonnull final Type type) {
51         final ConcreteType javaType = TypeUtils.getBaseYangType(type);
52         return GENERATORS.get(javaType.getFullyQualifiedName());
53     }
54
55     /**
56      * Return the type's class.
57      *
58      * @return A class object
59      */
60     @Nonnull protected final Class<T> getTypeClass() {
61         return type;
62     }
63
64     /**
65      * Return the type's fully-qualified name.
66      *
67      * @return Fully-qualified name
68      */
69     @Nonnull protected final String getTypeName() {
70         return type.getName();
71     }
72
73     /**
74      * Return the value in the native type from a particular Number instance.
75      *
76      * @param value Value as a Number
77      * @return Value in native format.
78      */
79     @Nonnull protected final T getValue(final Number value) {
80         if (type.isInstance(value)) {
81             return type.cast(value);
82         }
83
84         LOG.debug("Converting value {} from {} to {}", value, value.getClass(), type);
85         final T ret = convert(value);
86
87         // Check if the conversion lost any precision by performing conversion the other way around
88         final AbstractRangeGenerator<?> gen = GENERATORS.get(value.getClass().getName());
89         final Number check = gen.convert(ret);
90         if (!value.equals(check)) {
91             LOG.warn("Number class conversion from {} to {} truncated value {} to {}", value.getClass(), type, value, ret);
92         }
93
94         return ret;
95     }
96
97     // FIXME: Once BUG-3399 is fixed, we should never need this
98     protected abstract T convert(final Number value);
99
100     /**
101      * Format a value into a Java-compilable expression which results in the appropriate
102      * type.
103      *
104      * @param value Number value
105      * @return Java language string representation
106      */
107     @Nonnull protected abstract String format(final T value);
108
109     /**
110      * Generate the checker method source code.
111      * @param checkerName Name of the checker method.
112      * @param constraint Restrictions which need to be applied.
113      * @return Method source code.
114      */
115     @Nonnull protected abstract String generateRangeCheckerImplementation(@Nonnull final String checkerName,
116             @Nonnull final RangeConstraint<?> constraint);
117
118     private static String rangeCheckerName(final String member) {
119         return "check" + member + "Range";
120     }
121
122     public String generateRangeChecker(@Nonnull final String member, @Nonnull final RangeConstraint<?> constraint) {
123         return generateRangeCheckerImplementation(rangeCheckerName(member), constraint);
124     }
125
126     public String generateRangeCheckerCall(@Nonnull final String member, @Nonnull final String valueReference) {
127         return rangeCheckerName(member) + '(' + valueReference + ");\n";
128     }
129 }