From 8ed6de88988ae205978338f53874b67dd517c70f Mon Sep 17 00:00:00 2001 From: Martin Ciglan Date: Fri, 4 Nov 2016 16:04:37 +0100 Subject: [PATCH] Bug 1411-5 #3: MDSAL Binding2 Java API Generator - Range generators - dedicated folder Change-Id: I53d448049bdd0a0fcdc7e113b7c209699321fab9 Signed-off-by: Filip Gregor Signed-off-by: Martin Ciglan --- .../AbstractBigRangeGenerator.java | 74 ++++++++++ .../AbstractPrimitiveRangeGenerator.java | 114 ++++++++++++++++ .../AbstractRangeGenerator.java | 127 ++++++++++++++++++ .../AbstractSubIntegerRangeGenerator.java | 20 +++ .../BigDecimalRangeGenerator.java | 48 +++++++ .../BigIntegerRangeGenerator.java | 42 ++++++ .../rangeGenerators/ByteRangeGenerator.java | 19 +++ .../IntegerRangeGenerator.java | 24 ++++ .../rangeGenerators/LengthGenerator.java | 122 +++++++++++++++++ .../rangeGenerators/LongRangeGenerator.java | 25 ++++ .../rangeGenerators/ShortRangeGenerator.java | 19 +++ .../generator/rangeGenerators/TypeUtils.java | 59 ++++++++ 12 files changed, 693 insertions(+) create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractBigRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractPrimitiveRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractSubIntegerRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigDecimalRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigIntegerRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ByteRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/IntegerRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LengthGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LongRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ShortRangeGenerator.java create mode 100644 binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/TypeUtils.java diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractBigRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractBigRangeGenerator.java new file mode 100644 index 0000000000..0276bd57de --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractBigRangeGenerator.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +import com.google.common.collect.Range; +import java.util.Collection; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; + +/** + * Abstract base for generators which require instantiation of boundary values to check. + * These are implemented by generating an array constant within the class, which contains + * {@link Range} instances, which hold pre-instantiated boundary values. + * + * @param type of the class + */ +abstract class AbstractBigRangeGenerator> extends AbstractRangeGenerator { + private static final String RANGE = Range.class.getName(); + + protected AbstractBigRangeGenerator(final Class typeClass) { + super(typeClass); + } + + private StringBuilder itemType() { + return new StringBuilder(RANGE).append('<').append(getTypeName()).append('>'); + } + + private StringBuilder arrayType() { + return new StringBuilder(itemType()).append("[]"); + } + + @Override + protected final String generateRangeCheckerImplementation(final String checkerName, @Nonnull final Collection constraints) { + final String fieldName = checkerName.toUpperCase() + "_RANGES"; + final StringBuilder sb = new StringBuilder(); + + // Field to hold the Range objects in an array + sb.append("private static final ").append(arrayType()).append(' ').append(fieldName).append(";\n"); + + // Static initializer block for the array + sb.append("static {\n"); + sb.append(" @SuppressWarnings(\"unchecked\")\n"); + sb.append(" final ").append(arrayType()).append(" a = (").append(arrayType()) + .append(") java.lang.reflect.Array.newInstance(").append(RANGE).append(".class, ").append(constraints.size()).append(");\n"); + + int i = 0; + for (RangeConstraint r : constraints) { + final String min = format(getValue(r.getMin())); + final String max = format(getValue(r.getMax())); + + sb.append(" a[").append(i++).append("] = ").append(RANGE).append(".closed(").append(min).append(", ").append(max).append(");\n"); + } + + sb.append(" ").append(fieldName).append(" = a;\n"); + sb.append("}\n"); + + // Static enforcement method + sb.append("private static void ").append(checkerName).append("(final ").append(getTypeName()).append(" value) {\n"); + sb.append(" for (").append(itemType()).append(" r : ").append(fieldName).append(") {\n"); + sb.append(" if (r.contains(value)) {\n"); + sb.append(" return;\n"); + sb.append(" }\n"); + sb.append(" }\n"); + sb.append(" throw new IllegalArgumentException(String.format(\"Invalid range: %s, expected: %s.\", value, java.util.Arrays.asList(").append(fieldName).append(")));\n"); + sb.append("}\n"); + + return sb.toString(); + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractPrimitiveRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractPrimitiveRangeGenerator.java new file mode 100644 index 0000000000..419322d856 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractPrimitiveRangeGenerator.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Range; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +abstract class AbstractPrimitiveRangeGenerator> extends AbstractRangeGenerator { + private static final Logger LOG = LoggerFactory.getLogger(AbstractPrimitiveRangeGenerator.class); + private final String primitiveName; + private final T minValue; + private final T maxValue; + + protected AbstractPrimitiveRangeGenerator(final Class typeClass, final String primitiveName, final T minValue, final T maxValue) { + super(typeClass); + this.primitiveName = Preconditions.checkNotNull(primitiveName); + this.minValue = Preconditions.checkNotNull(minValue); + this.maxValue = Preconditions.checkNotNull(maxValue); + } + + /** + * Return the name of the primitive type, as known by the Java language. + * + * @return Primitive type name + */ + @Nonnull protected final String getPrimitiveName() { + return primitiveName; + } + + private boolean needsMaximumEnforcement(final T maxToEnforce) { + return maxValue.compareTo(maxToEnforce) > 0; + } + + private boolean needsMinimumEnforcement(final T minToEnforce) { + return minValue.compareTo(minToEnforce) < 0; + } + + private Collection createExpressions(final Collection constraints) { + final Collection ret = new ArrayList<>(constraints.size()); + + for (RangeConstraint r : constraints) { + final T min = getValue(r.getMin()); + final boolean needMin = needsMinimumEnforcement(min); + + final T max = getValue(r.getMax()); + final boolean needMax = needsMaximumEnforcement(max); + + if (!needMin && !needMax) { + LOG.debug("Type {} indicates [{}, {}] does not require enforcement", getTypeName(), min, max); + continue; + } + + final StringBuilder sb = new StringBuilder(); + if (needMin) { + sb.append("value >= ").append(format(min)); + } + if (needMax) { + if (needMin) { + sb.append(" && "); + } + sb.append("value <= ").append(format(max)); + } + + ret.add(sb.toString()); + } + + return ret; + } + + private String createRangeString(final Collection constraints) { + final List> ranges = new ArrayList<>(constraints.size()); + + for (RangeConstraint c : constraints) { + ranges.add(Range.closed(getValue(c.getMin()), getValue(c.getMax()))); + } + + return ranges.toString(); + } + + @Override + protected final String generateRangeCheckerImplementation(final String checkerName, final Collection constraints) { + final StringBuilder sb = new StringBuilder(); + final Collection expressions = createExpressions(constraints); + + sb.append("private static void ").append(checkerName).append("(final ").append(primitiveName).append(" value) {\n"); + + if (!expressions.isEmpty()) { + for (String exp : expressions) { + sb.append(" if (").append(exp).append(") {\n"); + sb.append(" return;\n"); + sb.append(" }\n"); + } + + sb.append(" throw new IllegalArgumentException(String.format(\"Invalid range: %s, expected: ") + .append(createRangeString(constraints)).append(".\", value));\n"); + } + + sb.append("}\n"); + + return sb.toString(); + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractRangeGenerator.java new file mode 100644 index 0000000000..7efd24587d --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractRangeGenerator.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import java.util.Collection; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.mdsal.binding2.model.api.ConcreteType; +import org.opendaylight.mdsal.binding2.model.api.Type; +import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractRangeGenerator> { + private static final Logger LOG = LoggerFactory.getLogger(AbstractRangeGenerator.class); + private static final Map> GENERATORS; + + private static void addGenerator(final Builder> b, final AbstractRangeGenerator generator) { + b.put(generator.getTypeClass().getCanonicalName(), generator); + } + + static { + final Builder> b = ImmutableMap.> builder(); + addGenerator(b, new ByteRangeGenerator()); + addGenerator(b, new ShortRangeGenerator()); + addGenerator(b, new IntegerRangeGenerator()); + addGenerator(b, new LongRangeGenerator()); + addGenerator(b, new BigDecimalRangeGenerator()); + addGenerator(b, new BigIntegerRangeGenerator()); + GENERATORS = b.build(); + } + + private final Class type; + + protected AbstractRangeGenerator(final Class typeClass) { + this.type = Preconditions.checkNotNull(typeClass); + } + + public static AbstractRangeGenerator forType(@Nonnull final Type type) { + final ConcreteType javaType = TypeUtils.getBaseYangType(type); + return GENERATORS.get(javaType.getFullyQualifiedName()); + } + + /** + * Return the type's class. + * + * @return A class object + */ + @Nonnull protected final Class getTypeClass() { + return type; + } + + /** + * Return the type's fully-qualified name. + * + * @return Fully-qualified name + */ + @Nonnull protected final String getTypeName() { + return type.getName(); + } + + /** + * Return the value in the native type from a particular Number instance. + * + * @param value Value as a Number + * @return Value in native format. + */ + @Nonnull protected final T getValue(final Number value) { + if (type.isInstance(value)) { + return type.cast(value); + } + + LOG.debug("Converting value {} from {} to {}", value, value.getClass(), type); + final T ret = convert(value); + + // Check if the conversion lost any precision by performing conversion the other way around + final AbstractRangeGenerator gen = GENERATORS.get(value.getClass().getName()); + final Number check = gen.convert(ret); + if (!value.equals(check)) { + LOG.warn("Number class conversion from {} to {} truncated value {} to {}", value.getClass(), type, value, ret); + } + + return ret; + } + + // FIXME: Once BUG-3399 is fixed, we should never need this + protected abstract T convert(final Number value); + + /** + * Format a value into a Java-compilable expression which results in the appropriate + * type. + * + * @param value Number value + * @return Java language string representation + */ + @Nonnull protected abstract String format(final T value); + + /** + * Generate the checker method source code. + * @param checkerName Name of the checker method. + * @param constraints Restrictions which need to be applied. + * @return Method source code. + */ + @Nonnull protected abstract String generateRangeCheckerImplementation(@Nonnull final String checkerName, @Nonnull final Collection constraints); + + private static String rangeCheckerName(final String member) { + return "check" + member + "Range"; + } + + public String generateRangeChecker(@Nonnull final String member, @Nonnull final Collection + constraints) { + Preconditions.checkArgument(!constraints.isEmpty(), "Restrictions may not be empty"); + return generateRangeCheckerImplementation(rangeCheckerName(member), constraints); + } + + public String generateRangeCheckerCall(@Nonnull final String member, @Nonnull final String valueReference) { + return rangeCheckerName(member) + '(' + valueReference + ");\n"; + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractSubIntegerRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractSubIntegerRangeGenerator.java new file mode 100644 index 0000000000..7455cabd02 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/AbstractSubIntegerRangeGenerator.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +abstract class AbstractSubIntegerRangeGenerator> extends AbstractPrimitiveRangeGenerator { + protected AbstractSubIntegerRangeGenerator(final Class typeClass, final String primitiveName, final T minValue, final T maxValue) { + super(typeClass, primitiveName, minValue, maxValue); + } + + @Override + protected final String format(final T value) { + // Make sure the number constant is cast to the corresponding primitive type + return '(' + getPrimitiveName() + ')' + value; + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigDecimalRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigDecimalRangeGenerator.java new file mode 100644 index 0000000000..6906e56ec5 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigDecimalRangeGenerator.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +import java.math.BigDecimal; +import java.math.BigInteger; + +final class BigDecimalRangeGenerator extends AbstractBigRangeGenerator { + BigDecimalRangeGenerator() { + super(BigDecimal.class); + } + + @Override + protected String format(final BigDecimal value) { + if (BigDecimal.ZERO.equals(value)) { + return "java.math.BigDecimal.ZERO"; + } + if (BigDecimal.ONE.equals(value)) { + return "java.math.BigDecimal.ONE"; + } + if (BigDecimal.TEN.equals(value)) { + return "java.math.BigDecimal.TEN"; + } + + // FIXME: can we do something better? + return "new java.math.BigDecimal(\"" + value + "\")"; + } + + @Override + protected BigDecimal convert(final Number value) { + if (value instanceof BigInteger) { + return new BigDecimal((BigInteger)value); + } else if (value instanceof Byte) { + return new BigDecimal(value.intValue()); + } else if (value instanceof Short) { + return new BigDecimal(value.intValue()); + } else if (value instanceof Integer) { + return new BigDecimal(value.intValue()); + } else { + return BigDecimal.valueOf(value.longValue()); + } + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigIntegerRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigIntegerRangeGenerator.java new file mode 100644 index 0000000000..8c8b238eb8 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/BigIntegerRangeGenerator.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +import java.math.BigInteger; + +final class BigIntegerRangeGenerator extends AbstractBigRangeGenerator { + BigIntegerRangeGenerator() { + super(BigInteger.class); + } + + @Override + protected String format(final BigInteger value) { + if (BigInteger.ZERO.equals(value)) { + return "java.math.BigInteger.ZERO"; + } + if (BigInteger.ONE.equals(value)) { + return "java.math.BigInteger.ONE"; + } + if (BigInteger.TEN.equals(value)) { + return "java.math.BigInteger.TEN"; + } + + // Check for conversion to long + final long l = value.longValue(); + if (value.equals(BigInteger.valueOf(l))) { + return "java.math.BigInteger.valueOf(" + l + "L)"; + } else { + return "new java.math.BigInteger(\"" + value.toString() + "\")"; + } + } + + @Override + protected BigInteger convert(final Number value) { + return BigInteger.valueOf(value.longValue()); + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ByteRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ByteRangeGenerator.java new file mode 100644 index 0000000000..26942f89e4 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ByteRangeGenerator.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +final class ByteRangeGenerator extends AbstractSubIntegerRangeGenerator { + ByteRangeGenerator() { + super(Byte.class, byte.class.getName(), Byte.MIN_VALUE, Byte.MAX_VALUE); + } + + @Override + protected Byte convert(final Number value) { + return value.byteValue(); + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/IntegerRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/IntegerRangeGenerator.java new file mode 100644 index 0000000000..54a50e27b9 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/IntegerRangeGenerator.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +final class IntegerRangeGenerator extends AbstractPrimitiveRangeGenerator { + IntegerRangeGenerator() { + super(Integer.class, int.class.getName(), Integer.MIN_VALUE, Integer.MAX_VALUE); + } + + @Override + protected String format(final Integer value) { + return value.toString(); + } + + @Override + protected Integer convert(final Number value) { + return value.intValue(); + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LengthGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LengthGenerator.java new file mode 100644 index 0000000000..cbecbafb85 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LengthGenerator.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +import com.google.common.collect.Range; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.mdsal.binding2.model.api.Type; +import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint; + +public final class LengthGenerator { + private LengthGenerator() { + throw new UnsupportedOperationException(); + } + + private static String lengthCheckerName(final String member) { + return "check" + member + "Length"; + } + + private static Collection createExpressions(final Collection constraints) { + final Collection ret = new ArrayList<>(constraints.size()); + + for (LengthConstraint l : constraints) { + final StringBuilder sb = new StringBuilder("length >"); + + // We have to deal with restrictions being out of integer's range + if (l.getMin().longValue() <= Integer.MAX_VALUE) { + sb.append('='); + } + sb.append(' ').append(l.getMin().intValue()); + + final int max = l.getMax().intValue(); + if (max < Integer.MAX_VALUE) { + sb.append(" && length <= ").append(max); + } + + ret.add(sb.toString()); + } + + return ret; + } + + private static String createLengthString(final Collection constraints) { + final List> ranges = new ArrayList<>(constraints.size()); + + for (LengthConstraint c : constraints) { + ranges.add(Range.closed(new BigInteger(c.getMin().toString()), new BigInteger(c.getMax().toString()))); + } + + return ranges.toString(); + } + + private static String generateArrayLengthChecker(final String member, final Collection constraints) { + final StringBuilder sb = new StringBuilder(); + final Collection expressions = createExpressions(constraints); + + sb.append("private static void ").append(lengthCheckerName(member)).append("(final byte[] value) {\n"); + + if (!expressions.isEmpty()) { + sb.append(" final int length = value.length;\n"); + + for (String exp : expressions) { + sb.append(" if (").append(exp).append(") {\n"); + sb.append(" return;\n"); + sb.append(" }\n"); + } + + sb.append(" throw new IllegalArgumentException(String.format(\"Invalid length: %s, expected: ") + .append(createLengthString(constraints)).append(".\", java.util.Arrays.toString(value)));\n"); + } + + sb.append("}\n"); + + return sb.toString(); + } + + private static String generateStringLengthChecker(final String member, final Collection constraints) { + final StringBuilder sb = new StringBuilder(); + final Collection expressions = createExpressions(constraints); + + sb.append("private static void ").append(lengthCheckerName(member)).append("(final String value) {\n"); + + if (!expressions.isEmpty()) { + sb.append(" final int length = value.length();\n"); + + for (String exp : expressions) { + sb.append(" if (").append(exp).append(") {\n"); + sb.append(" return;\n"); + sb.append(" }\n"); + } + + sb.append(" throw new IllegalArgumentException(String.format(\"Invalid length: %s, expected: ") + .append(createLengthString(constraints)).append(".\", value));\n"); + } + + sb.append("}\n"); + + return sb.toString(); + } + + public static String generateLengthChecker(final String member, final Type type, final Collection + constraints) { + if (TypeUtils.getBaseYangType(type).getName().contains("[")) { + return generateArrayLengthChecker(member, constraints); + } else { + return generateStringLengthChecker(member, constraints); + } + } + + public static String generateLengthCheckerCall(@Nullable final String member, @Nonnull final String valueReference) { + return lengthCheckerName(member) + '(' + valueReference + ");\n"; + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LongRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LongRangeGenerator.java new file mode 100644 index 0000000000..9c23c1b391 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/LongRangeGenerator.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +final class LongRangeGenerator extends AbstractPrimitiveRangeGenerator { + + protected LongRangeGenerator() { + super(Long.class, long.class.getName(), Long.MIN_VALUE, Long.MAX_VALUE); + } + + @Override + protected String format(final Long value) { + return value.toString() + 'L'; + } + + @Override + protected Long convert(final Number value) { + return value.longValue(); + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ShortRangeGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ShortRangeGenerator.java new file mode 100644 index 0000000000..eeff04c08e --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/ShortRangeGenerator.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +final class ShortRangeGenerator extends AbstractSubIntegerRangeGenerator { + ShortRangeGenerator() { + super(Short.class, short.class.getName(), Short.MIN_VALUE, Short.MAX_VALUE); + } + + @Override + protected Short convert(final Number value) { + return value.shortValue(); + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/TypeUtils.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/TypeUtils.java new file mode 100644 index 0000000000..79483da0b4 --- /dev/null +++ b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/rangeGenerators/TypeUtils.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding2.java.api.generator.rangeGenerators; + +import com.google.common.base.Preconditions; +import javax.annotation.Nonnull; +import org.opendaylight.mdsal.binding2.model.api.ConcreteType; +import org.opendaylight.mdsal.binding2.model.api.GeneratedProperty; +import org.opendaylight.mdsal.binding2.model.api.GeneratedTransferObject; +import org.opendaylight.mdsal.binding2.model.api.Type; + +/** + * Random utility methods for dealing with {@link Type} objects. + */ +final class TypeUtils { + private static final String VALUE_PROP = "value"; + + private TypeUtils() { + throw new UnsupportedOperationException(); + } + + /** + * Given a {@link Type} object lookup the base Java type which sits at the top + * of its type hierarchy. + * + * @param type Input Type object + * @return Resolved {@link ConcreteType} instance. + */ + static ConcreteType getBaseYangType(@Nonnull final Type type) { + // Already the correct type + if (type instanceof ConcreteType) { + return (ConcreteType) type; + } + + Preconditions.checkArgument(type instanceof GeneratedTransferObject, "Unsupported type %s", type); + + // Need to walk up the GTO chain to the root + GeneratedTransferObject rootGto = (GeneratedTransferObject) type; + while (rootGto.getSuperType() != null) { + rootGto = rootGto.getSuperType(); + } + + // Look for the 'value' property and return its type + for (GeneratedProperty s : rootGto.getProperties()) { + if (VALUE_PROP.equals(s.getName())) { + return (ConcreteType) s.getReturnType(); + } + } + + // Should never happen + throw new IllegalArgumentException(String.format("Type %s root %s properties %s do not include \"%s\"", + type, rootGto, rootGto.getProperties(), VALUE_PROP)); + } +} \ No newline at end of file -- 2.36.6