Improve Decimal64 range support
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / Decimal64RangeGenerator.java
1 /*
2  * Copyright (c) 2015 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.java.api.generator;
9
10 import com.google.common.collect.Range;
11 import java.lang.reflect.Array;
12 import java.util.Locale;
13 import java.util.Set;
14 import java.util.function.Function;
15 import org.opendaylight.yangtools.yang.binding.CodeHelpers;
16 import org.opendaylight.yangtools.yang.common.Decimal64;
17 import org.opendaylight.yangtools.yang.common.Uint16;
18 import org.opendaylight.yangtools.yang.common.Uint8;
19 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
20
21 /**
22  * Decimal64 boundary check generator. It requires instantiation of boundary values -- these are implemented by
23  * generating an array constant within the class, which contains {@link Range} instances, which hold pre-instantiated
24  * boundary values.
25  */
26 final class Decimal64RangeGenerator extends AbstractRangeGenerator<Decimal64> {
27     Decimal64RangeGenerator() {
28         super(Decimal64.class);
29     }
30
31     private static String range(final Function<Class<?>, String> classImporter) {
32         return classImporter.apply(Range.class);
33     }
34
35     private static String itemType(final Function<Class<?>, String> classImporter) {
36         return range(classImporter) + '<' + classImporter.apply(Decimal64.class) + '>';
37     }
38
39     private static String arrayType(final Function<Class<?>, String> classImporter) {
40         return itemType(classImporter) + "[]";
41     }
42
43     private static String format(final Function<Class<?>, String> classImporter, final Decimal64 value) {
44         return classImporter.apply(Decimal64.class) +  ".of(" + value.scale() + ", " + value.unscaledValue() + "L)";
45     }
46
47     @Override
48     @Deprecated
49     protected Decimal64 convert(final Number value) {
50         if (value instanceof Byte || value instanceof Short || value instanceof Integer
51             || value instanceof Uint8 || value instanceof Uint16) {
52             // FIXME: this is not quite right
53             return Decimal64.valueOf(1, value.intValue());
54         } else {
55             // FIXME: this is not quite right
56             return Decimal64.valueOf(1, value.longValue());
57         }
58     }
59
60     @Override
61     protected String generateRangeCheckerImplementation(final String checkerName,
62             final RangeConstraint<?> constraint, final Function<Class<?>, String> classImporter) {
63         final Set<? extends Range<? extends Number>> constraints = constraint.getAllowedRanges().asRanges();
64         final String fieldName = checkerName.toUpperCase(Locale.ENGLISH) + "_RANGES";
65         final StringBuilder sb = new StringBuilder();
66
67         // Field to hold the Range objects in an array
68         sb.append("private static final ").append(arrayType(classImporter)).append(' ').append(fieldName).append(";\n");
69
70         // Static initializer block for the array
71         sb.append("static {\n");
72         sb.append("    @SuppressWarnings(\"unchecked\")\n");
73         sb.append("    final ").append(arrayType(classImporter)).append(" a = (").append(arrayType(classImporter))
74             .append(") ").append(classImporter.apply(Array.class)).append(".newInstance(").append(range(classImporter))
75             .append(".class, ").append(constraints.size()).append(");\n");
76
77         int offset = 0;
78         for (Range<? extends Number> r : constraints) {
79             final String min = format(classImporter, getValue(r.lowerEndpoint()));
80             final String max = format(classImporter, getValue(r.upperEndpoint()));
81
82             sb.append("    a[").append(offset++).append("] = ").append(range(classImporter)).append(".closed(")
83                 .append(min).append(", ").append(max).append(");\n");
84         }
85
86         sb.append("    ").append(fieldName).append(" = a;\n");
87         sb.append("}\n");
88
89         // Static enforcement method
90         sb.append("private static void ").append(checkerName).append("(final ").append(getTypeName())
91             .append(" value) {\n");
92         sb.append("    for (").append(itemType(classImporter)).append(" r : ").append(fieldName).append(") {\n");
93         sb.append("        if (r.contains(value)) {\n");
94         sb.append("            return;\n");
95         sb.append("        }\n");
96         sb.append("    }\n");
97
98         sb.append("    ").append(classImporter.apply(CodeHelpers.class)).append(".throwInvalidRange(").append(fieldName)
99             .append(", value);\n");
100         sb.append("}\n");
101
102         return sb.toString();
103     }
104 }