2 * Copyright (c) 2013 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 org.opendaylight.yangtools.yang.model.util.BaseTypes.INT16_QNAME;
11 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.INT32_QNAME;
12 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.INT64_QNAME;
13 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.INT8_QNAME;
14 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT16_QNAME;
15 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT32_QNAME;
16 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT64_QNAME;
17 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT8_QNAME;
19 import com.google.common.base.CharMatcher;
20 import com.google.common.base.Joiner;
21 import com.google.common.base.Optional;
22 import com.google.common.base.Preconditions;
23 import com.google.common.base.Splitter;
24 import com.google.common.base.Strings;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.collect.Sets;
27 import com.google.common.io.BaseEncoding;
29 import java.math.BigDecimal;
30 import java.math.BigInteger;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
35 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
36 import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
37 import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
38 import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec;
39 import org.opendaylight.yangtools.yang.data.api.codec.EmptyCodec;
40 import org.opendaylight.yangtools.yang.data.api.codec.EnumCodec;
41 import org.opendaylight.yangtools.yang.data.api.codec.Int16Codec;
42 import org.opendaylight.yangtools.yang.data.api.codec.Int32Codec;
43 import org.opendaylight.yangtools.yang.data.api.codec.Int64Codec;
44 import org.opendaylight.yangtools.yang.data.api.codec.Int8Codec;
45 import org.opendaylight.yangtools.yang.data.api.codec.StringCodec;
46 import org.opendaylight.yangtools.yang.data.api.codec.Uint16Codec;
47 import org.opendaylight.yangtools.yang.data.api.codec.Uint32Codec;
48 import org.opendaylight.yangtools.yang.data.api.codec.Uint64Codec;
49 import org.opendaylight.yangtools.yang.data.api.codec.Uint8Codec;
50 import org.opendaylight.yangtools.yang.data.api.codec.UnionCodec;
51 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
52 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
53 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
54 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
55 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
56 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
57 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
58 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
59 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
60 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
61 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
62 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
64 public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
66 private static final Pattern intPattern = Pattern.compile("[+-]?[1-9][0-9]*$");
67 private static final Pattern hexPattern = Pattern.compile("[+-]?0[xX][0-9a-fA-F]+");
68 private static final Pattern octalPattern = Pattern.compile("[+-]?0[1-7][0-7]*$");
70 // For up to two characters, this is very fast
71 private static final CharMatcher X_MATCHER = CharMatcher.anyOf("xX");
73 private final Optional<T> typeDefinition;
74 private final Class<J> inputClass;
76 private static final int provideBase(final String integer) {
77 if (integer == null) {
78 throw new IllegalArgumentException("String representing integer number cannot be NULL");
81 if ((integer.length() == 1) && (integer.charAt(0) == '0')) {
85 final Matcher intMatcher = intPattern.matcher(integer);
86 if (intMatcher.matches()) {
89 final Matcher hexMatcher = hexPattern.matcher(integer);
90 if (hexMatcher.matches()) {
93 final Matcher octMatcher = octalPattern.matcher(integer);
94 if (octMatcher.matches()) {
97 String formatedMessage = String.format("Incorrect lexical representation of integer value: %s."
98 + "\nAn integer value can be defined as: "
99 + "\n - a decimal number,"
100 + "\n - a hexadecimal number (prefix 0x),"
101 + "\n - an octal number (prefix 0)."
102 + "\nSigned values are allowed. Spaces between digits are NOT allowed.", integer);
103 throw new NumberFormatException(formatedMessage);
109 private static String normalizeHexadecimal(final String hexInt) {
110 if (hexInt == null) {
111 throw new IllegalArgumentException(
112 "String representing integer number in Hexadecimal format cannot be NULL!");
115 return X_MATCHER.removeFrom(hexInt);
118 private static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
119 Optional.<BinaryTypeDefinition> absent());
121 private static final BooleanCodecStringImpl BOOLEAN_DEFAULT_CODEC = new BooleanCodecStringImpl(
122 Optional.<BooleanTypeDefinition> absent());
124 private static final DecimalCodecStringImpl DECIMAL64_DEFAULT_CODEC = new DecimalCodecStringImpl(
125 Optional.<DecimalTypeDefinition> absent());
127 private static final EmptyCodecStringImpl EMPTY_DEFAULT_CODEC = new EmptyCodecStringImpl(
128 Optional.<EmptyTypeDefinition> absent());
130 private static final Int8CodecStringImpl INT8_DEFAULT_CODEC = new Int8CodecStringImpl(
131 Optional.<IntegerTypeDefinition> absent());
133 private static final Int16CodecStringImpl INT16_DEFAULT_CODEC = new Int16CodecStringImpl(
134 Optional.<IntegerTypeDefinition> absent());
136 private static final Int32CodecStringImpl INT32_DEFAULT_CODEC = new Int32CodecStringImpl(
137 Optional.<IntegerTypeDefinition> absent());
139 private static final Int64CodecStringImpl INT64_DEFAULT_CODEC = new Int64CodecStringImpl(
140 Optional.<IntegerTypeDefinition> absent());
142 private static final StringCodecStringImpl STRING_DEFAULT_CODEC = new StringCodecStringImpl(
143 Optional.<StringTypeDefinition> absent());
145 private static final Uint8CodecStringImpl UINT8_DEFAULT_CODEC = new Uint8CodecStringImpl(
146 Optional.<UnsignedIntegerTypeDefinition> absent());
148 private static final Uint16CodecStringImpl UINT16_DEFAULT_CODEC = new Uint16CodecStringImpl(
149 Optional.<UnsignedIntegerTypeDefinition> absent());
151 private static final Uint32CodecStringImpl UINT32_DEFAULT_CODEC = new Uint32CodecStringImpl(
152 Optional.<UnsignedIntegerTypeDefinition> absent());
154 private static final Uint64CodecStringImpl UINT64_DEFAULT_CODEC = new Uint64CodecStringImpl(
155 Optional.<UnsignedIntegerTypeDefinition> absent());
158 public Class<J> getInputClass() {
162 protected TypeDefinitionAwareCodec(final Optional<T> typeDefinition, final Class<J> outputClass) {
163 Preconditions.checkArgument(outputClass != null, "Output class must be specified.");
164 this.typeDefinition = typeDefinition;
165 this.inputClass = outputClass;
168 public Optional<T> getTypeDefinition() {
169 return typeDefinition;
172 @SuppressWarnings({ "rawtypes", "unchecked" })
173 public static final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> from(final TypeDefinition typeDefinition) {
174 return fromType(typeDefinition);
177 @SuppressWarnings("unchecked")
178 public static final <T extends TypeDefinition<T>> TypeDefinitionAwareCodec<?, T> fromType(final T typeDefinition) {
179 T superType = typeDefinition;
180 while (superType.getBaseType() != null) {
181 superType = superType.getBaseType();
184 @SuppressWarnings("rawtypes")
185 TypeDefinitionAwareCodec codec = null;
187 if (superType instanceof BinaryTypeDefinition) {
188 codec = BINARY_DEFAULT_CODEC;
189 } else if (superType instanceof BitsTypeDefinition) {
190 codec = new BitsCodecStringImpl( Optional.of( (BitsTypeDefinition)superType ) );
191 } else if (superType instanceof BooleanTypeDefinition) {
192 codec = BOOLEAN_DEFAULT_CODEC;
193 } else if (superType instanceof DecimalTypeDefinition) {
194 codec = DECIMAL64_DEFAULT_CODEC;
195 } else if (superType instanceof EmptyTypeDefinition) {
196 codec = EMPTY_DEFAULT_CODEC;
197 } else if (superType instanceof EnumTypeDefinition) {
198 codec = new EnumCodecStringImpl( Optional.of( (EnumTypeDefinition)superType ) );
199 } else if (superType instanceof IntegerTypeDefinition) {
200 if (INT8_QNAME.equals(superType.getQName())) {
201 codec = INT8_DEFAULT_CODEC;
202 } else if (INT16_QNAME.equals(superType.getQName())) {
203 codec = INT16_DEFAULT_CODEC;
204 } else if (INT32_QNAME.equals(superType.getQName())) {
205 codec = INT32_DEFAULT_CODEC;
206 } else if (INT64_QNAME.equals(superType.getQName())) {
207 codec = INT64_DEFAULT_CODEC;
209 } else if (superType instanceof StringTypeDefinition) {
210 codec = STRING_DEFAULT_CODEC;
211 } else if (superType instanceof UnionTypeDefinition) {
212 codec = new UnionCodecStringImpl( Optional.of( (UnionTypeDefinition)superType ) );
213 } else if (superType instanceof UnsignedIntegerTypeDefinition) {
214 if (UINT8_QNAME.equals(superType.getQName())) {
215 codec = UINT8_DEFAULT_CODEC;
217 if (UINT16_QNAME.equals(superType.getQName())) {
218 codec = UINT16_DEFAULT_CODEC;
220 if (UINT32_QNAME.equals(superType.getQName())) {
221 codec = UINT32_DEFAULT_CODEC;
223 if (UINT64_QNAME.equals(superType.getQName())) {
224 codec = UINT64_DEFAULT_CODEC;
231 public static class BooleanCodecStringImpl extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
232 implements BooleanCodec<String> {
234 protected BooleanCodecStringImpl(final Optional<BooleanTypeDefinition> typeDef) {
235 super(typeDef, Boolean.class);
239 public String serialize(final Boolean data) {
240 return data == null ? "" : data.toString();
244 public Boolean deserialize(final String stringRepresentation) {
245 return Boolean.valueOf(stringRepresentation);
249 public static class Uint8CodecStringImpl extends TypeDefinitionAwareCodec<Short, UnsignedIntegerTypeDefinition>
250 implements Uint8Codec<String> {
252 protected Uint8CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
253 super(typeDef, Short.class);
257 public String serialize(final Short data) {
258 return data == null ? "" : data.toString();
262 public Short deserialize(final String stringRepresentation) {
263 int base = provideBase(stringRepresentation);
265 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
267 return Short.valueOf(stringRepresentation, base);
271 public static class Uint16CodecStringImpl extends TypeDefinitionAwareCodec<Integer, UnsignedIntegerTypeDefinition>
272 implements Uint16Codec<String> {
273 protected Uint16CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
274 super(typeDef, Integer.class);
278 public Integer deserialize(final String stringRepresentation) {
279 int base = provideBase(stringRepresentation);
281 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
283 return Integer.valueOf(stringRepresentation, base);
287 public String serialize(final Integer data) {
288 return data == null ? "" : data.toString();
292 public static class Uint32CodecStringImpl extends TypeDefinitionAwareCodec<Long, UnsignedIntegerTypeDefinition>
293 implements Uint32Codec<String> {
295 protected Uint32CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
296 super(typeDef, Long.class);
300 public Long deserialize(final String stringRepresentation) {
301 int base = provideBase(stringRepresentation);
303 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
305 return Long.valueOf(stringRepresentation, base);
309 public String serialize(final Long data) {
310 return data == null ? "" : data.toString();
314 public static class Uint64CodecStringImpl extends
315 TypeDefinitionAwareCodec<BigInteger, UnsignedIntegerTypeDefinition> implements Uint64Codec<String> {
317 protected Uint64CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
318 super(typeDef, BigInteger.class);
322 public BigInteger deserialize(final String stringRepresentation) {
323 int base = provideBase(stringRepresentation);
325 return new BigInteger(normalizeHexadecimal(stringRepresentation), base);
327 return new BigInteger(stringRepresentation, base);
331 public String serialize(final BigInteger data) {
332 return data == null ? "" : data.toString();
336 public static class StringCodecStringImpl extends TypeDefinitionAwareCodec<String, StringTypeDefinition> implements
337 StringCodec<String> {
339 protected StringCodecStringImpl(final Optional<StringTypeDefinition> typeDef) {
340 super(typeDef, String.class);
344 public String deserialize(final String stringRepresentation) {
345 return stringRepresentation == null ? "" :stringRepresentation;
349 public String serialize(final String data) {
350 return data == null ? "" : data.toString();
354 public static class Int16CodecStringImpl extends TypeDefinitionAwareCodec<Short, IntegerTypeDefinition> implements
357 protected Int16CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
358 super(typeDef, Short.class);
362 public Short deserialize(final String stringRepresentation) {
363 int base = provideBase(stringRepresentation);
365 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
367 return Short.valueOf(stringRepresentation, base);
371 public String serialize(final Short data) {
372 return data == null ? "" : data.toString();
376 public static class Int32CodecStringImpl extends TypeDefinitionAwareCodec<Integer, IntegerTypeDefinition> implements
379 protected Int32CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
380 super(typeDef, Integer.class);
384 public Integer deserialize(final String stringRepresentation) {
385 int base = provideBase(stringRepresentation);
387 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
389 return Integer.valueOf(stringRepresentation, base);
393 public String serialize(final Integer data) {
394 return data == null ? "" : data.toString();
398 public static class Int64CodecStringImpl extends TypeDefinitionAwareCodec<Long, IntegerTypeDefinition> implements
401 protected Int64CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
402 super(typeDef, Long.class);
406 public Long deserialize(final String stringRepresentation) {
407 int base = provideBase(stringRepresentation);
409 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
411 return Long.valueOf(stringRepresentation, base);
415 public String serialize(final Long data) {
416 return data == null ? "" : data.toString();
420 public static class Int8CodecStringImpl extends TypeDefinitionAwareCodec<Byte, IntegerTypeDefinition> implements
423 protected Int8CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
424 super(typeDef, Byte.class);
428 public Byte deserialize(final String stringRepresentation) {
429 int base = provideBase(stringRepresentation);
431 return Byte.valueOf(normalizeHexadecimal(stringRepresentation), base);
433 return Byte.valueOf(stringRepresentation, base);
437 public String serialize(final Byte data) {
438 return data == null ? "" : data.toString();
442 public static class EmptyCodecStringImpl extends TypeDefinitionAwareCodec<Void, EmptyTypeDefinition> implements
445 protected EmptyCodecStringImpl(final Optional<EmptyTypeDefinition> typeDef) {
446 super(typeDef, Void.class);
450 public String serialize(final Void data) {
455 public Void deserialize(final String stringRepresentation) {
456 Preconditions.checkArgument( Strings.isNullOrEmpty( stringRepresentation ),
457 "The value must be empty" );
462 public static final class BinaryCodecStringImpl extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
463 implements BinaryCodec<String> {
465 protected BinaryCodecStringImpl(final Optional<BinaryTypeDefinition> typeDef) {
466 super(typeDef, byte[].class);
470 public String serialize(final byte[] data) {
471 return data == null ? "" : BaseEncoding.base64().encode(data);
475 public byte[] deserialize(final String stringRepresentation) {
476 return stringRepresentation == null ? null :
477 BaseEncoding.base64().decode(stringRepresentation);
481 public static final class BitsCodecStringImpl extends TypeDefinitionAwareCodec<Set<String>, BitsTypeDefinition>
482 implements BitsCodec<String> {
484 public static final Joiner JOINER = Joiner.on(" ").skipNulls();
485 public static final Splitter SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
487 @SuppressWarnings("unchecked")
488 protected BitsCodecStringImpl(final Optional<BitsTypeDefinition> typeDef) {
489 super(typeDef, (Class<Set<String>>) ((Class<?>) Set.class));
493 public String serialize(final Set<String> data) {
494 return data == null ? "" : JOINER.join(data);
498 public Set<String> deserialize(final String stringRepresentation) {
499 if (stringRepresentation == null) {
500 return ImmutableSet.of();
503 Iterable<String> strings = SPLITTER.split(stringRepresentation);
505 if( getTypeDefinition().isPresent() ) {
506 Set<String> allowedNames = Sets.newHashSet();
507 for( BitsTypeDefinition.Bit bit: getTypeDefinition().get().getBits() ) {
508 allowedNames.add( bit.getName() );
511 for( String bit: strings ) {
512 if( !allowedNames.contains( bit ) ) {
513 throw new IllegalArgumentException(
514 "Invalid value \"" + bit + "\" for bits type. Allowed values are: " +
520 return ImmutableSet.copyOf(strings);
524 public static class EnumCodecStringImpl extends TypeDefinitionAwareCodec<String, EnumTypeDefinition> implements
527 protected EnumCodecStringImpl(final Optional<EnumTypeDefinition> typeDef) {
528 super(typeDef, String.class);
532 public String deserialize(final String stringRepresentation) {
533 if( getTypeDefinition().isPresent() ) {
534 Set<String> allowedNames = Sets.newHashSet();
535 for( EnumPair pair: getTypeDefinition().get().getValues() ) {
536 allowedNames.add( pair.getName() );
539 if( !allowedNames.contains( stringRepresentation ) ) {
540 throw new IllegalArgumentException(
541 "Invalid value \"" + stringRepresentation + "\" for enum type. Allowed values are: " +
546 return stringRepresentation;
550 public String serialize(final String data) {
551 return data == null ? "" : data;
555 public static class DecimalCodecStringImpl extends TypeDefinitionAwareCodec<BigDecimal, DecimalTypeDefinition>
556 implements DecimalCodec<String> {
558 protected DecimalCodecStringImpl(final Optional<DecimalTypeDefinition> typeDef) {
559 super(typeDef, BigDecimal.class);
563 public String serialize(final BigDecimal data) {
564 return data == null ? "" : data.toString();
568 public BigDecimal deserialize(final String stringRepresentation) {
569 Preconditions.checkArgument( stringRepresentation != null , "Input cannot be null" );
570 return new BigDecimal(stringRepresentation);
574 public static class UnionCodecStringImpl extends TypeDefinitionAwareCodec<Object, UnionTypeDefinition> implements
577 protected UnionCodecStringImpl(final Optional<UnionTypeDefinition> typeDef) {
578 super(typeDef, Object.class);
582 public String serialize(final Object data) {
583 return data == null ? "" : data.toString();
587 public Object deserialize(final String stringRepresentation) {
588 if( getTypeDefinition().isPresent() ) {
589 boolean valid = false;
590 for( TypeDefinition<?> type: getTypeDefinition().get().getTypes() ) {
591 TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwareCodec = from( type );
592 if( typeAwareCodec == null ) {
593 // This is a type for which we have no codec (eg identity ref) so we'll say it's valid
594 // but we'll continue in case there's another type for which we do have a codec.
600 typeAwareCodec.deserialize( stringRepresentation );
604 catch( Exception e ) {
605 // invalid - try the next union type.
610 throw new IllegalArgumentException(
611 "Invalid value \"" + stringRepresentation + "\" for union type." );
615 return stringRepresentation;