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 static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.CharMatcher;
14 import com.google.common.collect.RangeSet;
15 import java.util.Optional;
16 import java.util.regex.Pattern;
17 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
18 import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
19 import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition;
21 import org.opendaylight.yangtools.yang.model.api.type.Int8TypeDefinition;
22 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
24 import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
31 * Do not use this class outside of yangtools, its presence does not fall into the API stability contract.
34 public abstract class AbstractIntegerStringCodec<N extends Number & Comparable<N>, T extends TypeDefinition<T>>
35 extends TypeDefinitionAwareCodec<N, T> {
37 private static final Pattern INT_PATTERN = Pattern.compile("[+-]?[1-9][0-9]*$");
38 private static final Pattern HEX_PATTERN = Pattern.compile("[+-]?0[xX][0-9a-fA-F]+");
39 private static final Pattern OCT_PATTERN = Pattern.compile("[+-]?0[1-7][0-7]*$");
41 // For up to two characters, this is very fast
42 private static final CharMatcher X_MATCHER = CharMatcher.anyOf("xX");
44 private static final String INCORRECT_LEXICAL_REPRESENTATION =
45 "Incorrect lexical representation of integer value: %s."
46 + "\nAn integer value can be defined as: "
47 + "\n - a decimal number,"
48 + "\n - a hexadecimal number (prefix 0x)," + "%n - an octal number (prefix 0)."
49 + "\nSigned values are allowed. Spaces between digits are NOT allowed.";
51 private final RangeSet<N> rangeConstraints;
53 AbstractIntegerStringCodec(final Optional<T> typeDefinition, final Optional<RangeConstraint<?>> constraint,
54 final Class<N> outputClass) {
55 super(typeDefinition, outputClass);
56 rangeConstraints = (RangeSet<N>) constraint.map(RangeConstraint::getAllowedRanges).orElse(null);
59 public static AbstractIntegerStringCodec<?, ? extends IntegerTypeDefinition<?, ?>> from(
60 final IntegerTypeDefinition<?, ?> type) {
61 if (type instanceof Int8TypeDefinition) {
62 return new Int8StringCodec(Optional.of((Int8TypeDefinition) type));
63 } else if (type instanceof Int16TypeDefinition) {
64 return new Int16StringCodec(Optional.of((Int16TypeDefinition) type));
65 } else if (type instanceof Int32TypeDefinition) {
66 return new Int32StringCodec(Optional.of((Int32TypeDefinition) type));
67 } else if (type instanceof Int64TypeDefinition) {
68 return new Int64StringCodec(Optional.of((Int64TypeDefinition) type));
70 throw new IllegalArgumentException("Unsupported type: " + type);
74 public static AbstractIntegerStringCodec<?, ? extends UnsignedIntegerTypeDefinition<?, ?>> from(
75 final UnsignedIntegerTypeDefinition<?, ?> type) {
76 if (type instanceof Uint8TypeDefinition) {
77 return new Uint8StringCodec(Optional.of((Uint8TypeDefinition) type));
78 } else if (type instanceof Uint16TypeDefinition) {
79 return new Uint16StringCodec(Optional.of((Uint16TypeDefinition) type));
80 } else if (type instanceof Uint32TypeDefinition) {
81 return new Uint32StringCodec(Optional.of((Uint32TypeDefinition) type));
82 } else if (type instanceof Uint64TypeDefinition) {
83 return new Uint64StringCodec(Optional.of((Uint64TypeDefinition) type));
85 throw new IllegalArgumentException("Unsupported type: " + type);
90 public final N deserialize(final String stringRepresentation) {
91 final int base = provideBase(stringRepresentation);
94 deserialized = deserialize(normalizeHexadecimal(stringRepresentation),base);
96 deserialized = deserialize(stringRepresentation,base);
98 validate(deserialized);
103 * Deserializes value from supplied string representation is supplied radix. See
104 * {@link Integer#parseInt(String, int)} for in-depth description about string and radix relationship.
106 * @param stringRepresentation String representation
107 * @param radix numeric base.
108 * @return Deserialized value.
110 abstract N deserialize(String stringRepresentation, int radix);
112 private void validate(final N value) {
113 if (rangeConstraints != null) {
114 checkArgument(rangeConstraints.contains(value), "Value '%s' is not in required ranges %s",
115 value, rangeConstraints);
119 protected static Optional<RangeConstraint<?>> extractRange(final IntegerTypeDefinition<?, ?> type) {
120 return type == null ? Optional.empty() : type.getRangeConstraint();
123 protected static Optional<RangeConstraint<?>> extractRange(final UnsignedIntegerTypeDefinition<?, ?> type) {
124 return type == null ? Optional.empty() : type.getRangeConstraint();
127 private static int provideBase(final String integer) {
128 checkArgument(integer != null, "String representing integer number cannot be NULL");
130 if (integer.length() == 1 && integer.charAt(0) == '0') {
132 } else if (INT_PATTERN.matcher(integer).matches()) {
134 } else if (HEX_PATTERN.matcher(integer).matches()) {
136 } else if (OCT_PATTERN.matcher(integer).matches()) {
139 throw new NumberFormatException(String.format(INCORRECT_LEXICAL_REPRESENTATION, integer));
143 private static String normalizeHexadecimal(final String hexInt) {
144 checkArgument(hexInt != null, "String representing integer number in Hexadecimal format cannot be NULL!");
145 return X_MATCHER.removeFrom(hexInt);