2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.data.impl.codec;
10 import com.google.common.base.CharMatcher;
11 import com.google.common.base.Optional;
12 import com.google.common.collect.Range;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
18 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
19 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
21 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
23 abstract class AbstractIntegerStringCodec<N extends Number & Comparable<N>, T extends TypeDefinition<T>> extends TypeDefinitionAwareCodec<N, T>{
25 private static final Pattern intPattern = Pattern.compile("[+-]?[1-9][0-9]*$");
26 private static final Pattern hexPattern = Pattern.compile("[+-]?0[xX][0-9a-fA-F]+");
27 private static final Pattern octalPattern = Pattern.compile("[+-]?0[1-7][0-7]*$");
29 // For up to two characters, this is very fast
30 private static final CharMatcher X_MATCHER = CharMatcher.anyOf("xX");
32 private static final String INCORRECT_LEXICAL_REPRESENTATION = "Incorrect lexical representation of integer value: %s."
33 + "\nAn integer value can be defined as: "
34 + "\n - a decimal number,"
35 + "\n - a hexadecimal number (prefix 0x)," + "%n - an octal number (prefix 0)."
36 + "\nSigned values are allowed. Spaces between digits are NOT allowed.";
39 private final List<Range<N>> rangeConstraints;
41 protected AbstractIntegerStringCodec(final Optional<T> typeDefinition, final List<RangeConstraint> constraints , final Class<N> outputClass) {
42 super(typeDefinition, outputClass);
43 if(constraints.isEmpty()) {
44 rangeConstraints = Collections.emptyList();
46 final ArrayList<Range<N>> builder = new ArrayList<>(constraints.size());
47 for(final RangeConstraint yangConstraint : constraints) {
48 builder.add(createRange(yangConstraint.getMin(),yangConstraint.getMax()));
50 rangeConstraints = builder;
55 private Range<N> createRange(final Number yangMin, final Number yangMax) {
56 final N min = convertValue(yangMin);
57 final N max = convertValue(yangMax);
58 return Range.closed(min, max);
62 public final N deserialize(final String stringRepresentation) {
63 final int base = provideBase(stringRepresentation);
66 deserialized = deserialize(normalizeHexadecimal(stringRepresentation),base);
68 deserialized = deserialize(stringRepresentation,base);
70 validate(deserialized);
75 private final void validate(final N value) {
76 if (rangeConstraints.isEmpty()) {
79 for (final Range<N> constraint : rangeConstraints) {
80 if (constraint.contains(value)) {
84 // FIXME: Provide better error report.
85 throw new IllegalArgumentException("Value is not in required range.");
89 * Deserializes value from supplied string representation
92 * See {@link Integer#parseInt(String, int)} for in-depth
93 * description about string and radix relationship.
95 * @param stringRepresentation String representation
96 * @param radix numeric base.
97 * @return Deserialized value.
99 protected abstract N deserialize(String stringRepresentation, int radix);
101 protected abstract N convertValue(Number value);
104 protected static List<RangeConstraint> extractRange(final IntegerTypeDefinition type) {
106 return Collections.emptyList();
108 return type.getRangeConstraints();
111 protected static List<RangeConstraint> extractRange(final UnsignedIntegerTypeDefinition type) {
113 return Collections.emptyList();
115 return type.getRangeConstraints();
118 private static final int provideBase(final String integer) {
119 if (integer == null) {
120 throw new IllegalArgumentException("String representing integer number cannot be NULL");
123 if ((integer.length() == 1) && (integer.charAt(0) == '0')) {
127 final Matcher intMatcher = intPattern.matcher(integer);
128 if (intMatcher.matches()) {
131 final Matcher hexMatcher = hexPattern.matcher(integer);
132 if (hexMatcher.matches()) {
135 final Matcher octMatcher = octalPattern.matcher(integer);
136 if (octMatcher.matches()) {
139 final String formatedMessage =
140 String.format(INCORRECT_LEXICAL_REPRESENTATION, integer);
141 throw new NumberFormatException(formatedMessage);
144 private static String normalizeHexadecimal(final String hexInt) {
145 if (hexInt == null) {
146 throw new IllegalArgumentException(
147 "String representing integer number in Hexadecimal format cannot be NULL!");
150 return X_MATCHER.removeFrom(hexInt);