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.Joiner;
20 import com.google.common.base.Optional;
21 import com.google.common.base.Preconditions;
22 import com.google.common.base.Splitter;
23 import com.google.common.base.Strings;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.collect.Sets;
26 import com.google.common.io.BaseEncoding;
27 import java.math.BigDecimal;
28 import java.math.BigInteger;
30 import javax.xml.bind.DatatypeConverter;
31 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
32 import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
33 import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
34 import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec;
35 import org.opendaylight.yangtools.yang.data.api.codec.EmptyCodec;
36 import org.opendaylight.yangtools.yang.data.api.codec.EnumCodec;
37 import org.opendaylight.yangtools.yang.data.api.codec.Int16Codec;
38 import org.opendaylight.yangtools.yang.data.api.codec.Int32Codec;
39 import org.opendaylight.yangtools.yang.data.api.codec.Int64Codec;
40 import org.opendaylight.yangtools.yang.data.api.codec.Int8Codec;
41 import org.opendaylight.yangtools.yang.data.api.codec.StringCodec;
42 import org.opendaylight.yangtools.yang.data.api.codec.Uint16Codec;
43 import org.opendaylight.yangtools.yang.data.api.codec.Uint32Codec;
44 import org.opendaylight.yangtools.yang.data.api.codec.Uint64Codec;
45 import org.opendaylight.yangtools.yang.data.api.codec.Uint8Codec;
46 import org.opendaylight.yangtools.yang.data.api.codec.UnionCodec;
47 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
48 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
49 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
50 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
51 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
52 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
53 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
54 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
55 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
56 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
57 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
58 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
60 public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
64 private final Optional<T> typeDefinition;
65 private final Class<J> inputClass;
69 private static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
70 Optional.<BinaryTypeDefinition> absent());
72 private static final BooleanCodecStringImpl BOOLEAN_DEFAULT_CODEC = new BooleanCodecStringImpl(
73 Optional.<BooleanTypeDefinition> absent());
75 private static final DecimalCodecStringImpl DECIMAL64_DEFAULT_CODEC = new DecimalCodecStringImpl(
76 Optional.<DecimalTypeDefinition> absent());
78 private static final EmptyCodecStringImpl EMPTY_DEFAULT_CODEC = new EmptyCodecStringImpl(
79 Optional.<EmptyTypeDefinition> absent());
81 private static final Int8CodecStringImpl INT8_DEFAULT_CODEC = new Int8CodecStringImpl(
82 Optional.<IntegerTypeDefinition> absent());
84 private static final Int16CodecStringImpl INT16_DEFAULT_CODEC = new Int16CodecStringImpl(
85 Optional.<IntegerTypeDefinition> absent());
87 private static final Int32CodecStringImpl INT32_DEFAULT_CODEC = new Int32CodecStringImpl(
88 Optional.<IntegerTypeDefinition> absent());
90 private static final Int64CodecStringImpl INT64_DEFAULT_CODEC = new Int64CodecStringImpl(
91 Optional.<IntegerTypeDefinition> absent());
93 private static final StringCodecStringImpl STRING_DEFAULT_CODEC = new StringCodecStringImpl(
94 Optional.<StringTypeDefinition> absent());
96 private static final Uint8CodecStringImpl UINT8_DEFAULT_CODEC = new Uint8CodecStringImpl(
97 Optional.<UnsignedIntegerTypeDefinition> absent());
99 private static final Uint16CodecStringImpl UINT16_DEFAULT_CODEC = new Uint16CodecStringImpl(
100 Optional.<UnsignedIntegerTypeDefinition> absent());
102 private static final Uint32CodecStringImpl UINT32_DEFAULT_CODEC = new Uint32CodecStringImpl(
103 Optional.<UnsignedIntegerTypeDefinition> absent());
105 private static final Uint64CodecStringImpl UINT64_DEFAULT_CODEC = new Uint64CodecStringImpl(
106 Optional.<UnsignedIntegerTypeDefinition> absent());
109 public Class<J> getInputClass() {
113 protected TypeDefinitionAwareCodec(final Optional<T> typeDefinition, final Class<J> outputClass) {
114 Preconditions.checkArgument(outputClass != null, "Output class must be specified.");
115 this.typeDefinition = typeDefinition;
116 this.inputClass = outputClass;
119 public Optional<T> getTypeDefinition() {
120 return typeDefinition;
123 @SuppressWarnings({ "rawtypes", "unchecked" })
124 public static final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> from(final TypeDefinition typeDefinition) {
125 return fromType(typeDefinition);
128 @SuppressWarnings("unchecked")
129 public static final <T extends TypeDefinition<T>> TypeDefinitionAwareCodec<?, T> fromType(final T typeDefinition) {
130 T superType = typeDefinition;
131 while (superType.getBaseType() != null) {
132 superType = superType.getBaseType();
135 @SuppressWarnings("rawtypes")
136 TypeDefinitionAwareCodec codec = null;
138 if (superType instanceof BinaryTypeDefinition) {
139 codec = BINARY_DEFAULT_CODEC;
140 } else if (superType instanceof BitsTypeDefinition) {
141 codec = new BitsCodecStringImpl( Optional.of( (BitsTypeDefinition)superType ) );
142 } else if (superType instanceof BooleanTypeDefinition) {
143 codec = BOOLEAN_DEFAULT_CODEC;
144 } else if (superType instanceof DecimalTypeDefinition) {
145 codec = DECIMAL64_DEFAULT_CODEC;
146 } else if (superType instanceof EmptyTypeDefinition) {
147 codec = EMPTY_DEFAULT_CODEC;
148 } else if (superType instanceof EnumTypeDefinition) {
149 codec = new EnumCodecStringImpl( Optional.of( (EnumTypeDefinition)superType ) );
150 } else if (superType instanceof IntegerTypeDefinition) {
151 if (INT8_QNAME.equals(superType.getQName())) {
152 codec = INT8_DEFAULT_CODEC;
153 } else if (INT16_QNAME.equals(superType.getQName())) {
154 codec = INT16_DEFAULT_CODEC;
155 } else if (INT32_QNAME.equals(superType.getQName())) {
156 codec = INT32_DEFAULT_CODEC;
157 } else if (INT64_QNAME.equals(superType.getQName())) {
158 codec = INT64_DEFAULT_CODEC;
160 } else if (superType instanceof StringTypeDefinition) {
161 codec = STRING_DEFAULT_CODEC;
162 } else if (superType instanceof UnionTypeDefinition) {
163 codec = new UnionCodecStringImpl( Optional.of( (UnionTypeDefinition)superType ) );
164 } else if (superType instanceof UnsignedIntegerTypeDefinition) {
165 if (UINT8_QNAME.equals(superType.getQName())) {
166 codec = UINT8_DEFAULT_CODEC;
168 if (UINT16_QNAME.equals(superType.getQName())) {
169 codec = UINT16_DEFAULT_CODEC;
171 if (UINT32_QNAME.equals(superType.getQName())) {
172 codec = UINT32_DEFAULT_CODEC;
174 if (UINT64_QNAME.equals(superType.getQName())) {
175 codec = UINT64_DEFAULT_CODEC;
182 public static class BooleanCodecStringImpl extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
183 implements BooleanCodec<String> {
185 protected BooleanCodecStringImpl(final Optional<BooleanTypeDefinition> typeDef) {
186 super(typeDef, Boolean.class);
190 public String serialize(final Boolean data) {
191 return data == null ? "" : data.toString();
195 public Boolean deserialize(final String stringRepresentation) {
196 return Boolean.valueOf(stringRepresentation);
200 public static class Uint8CodecStringImpl extends AbstractIntegerStringCodec<Short, UnsignedIntegerTypeDefinition>
201 implements Uint8Codec<String> {
203 protected Uint8CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
204 super(typeDef, Short.class);
208 public String serialize(final Short data) {
209 return data == null ? "" : data.toString();
213 public Short deserialize(final String stringRepresentation,final int base) {
214 return Short.valueOf(stringRepresentation, base);
218 public static class Uint16CodecStringImpl extends AbstractIntegerStringCodec<Integer, UnsignedIntegerTypeDefinition>
219 implements Uint16Codec<String> {
220 protected Uint16CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
221 super(typeDef, Integer.class);
225 public Integer deserialize(final String stringRepresentation, final int base) {
226 return Integer.valueOf(stringRepresentation, base);
230 public String serialize(final Integer data) {
231 return data == null ? "" : data.toString();
235 public static class Uint32CodecStringImpl extends AbstractIntegerStringCodec<Long, UnsignedIntegerTypeDefinition>
236 implements Uint32Codec<String> {
238 protected Uint32CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
239 super(typeDef, Long.class);
243 public Long deserialize(final String stringRepresentation, final int base) {
244 return Long.valueOf(stringRepresentation, base);
248 public String serialize(final Long data) {
249 return data == null ? "" : data.toString();
253 public static class Uint64CodecStringImpl extends AbstractIntegerStringCodec<BigInteger, UnsignedIntegerTypeDefinition> implements Uint64Codec<String> {
255 protected Uint64CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
256 super(typeDef, BigInteger.class);
260 public BigInteger deserialize(final String stringRepresentation, final int base) {
261 return new BigInteger(stringRepresentation, base);
265 public String serialize(final BigInteger data) {
266 return data == null ? "" : data.toString();
270 public static class StringCodecStringImpl extends TypeDefinitionAwareCodec<String, StringTypeDefinition> implements
271 StringCodec<String> {
273 protected StringCodecStringImpl(final Optional<StringTypeDefinition> typeDef) {
274 super(typeDef, String.class);
278 public String deserialize(final String stringRepresentation) {
279 return stringRepresentation == null ? "" : stringRepresentation;
283 public String serialize(final String data) {
284 return data == null ? "" : data;
288 public static class Int16CodecStringImpl extends AbstractIntegerStringCodec<Short, IntegerTypeDefinition> implements
291 protected Int16CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
292 super(typeDef, Short.class);
296 public Short deserialize(final String stringRepresentation, final int base) {
297 return Short.valueOf(stringRepresentation, base);
301 public String serialize(final Short data) {
302 return data == null ? "" : data.toString();
306 public static class Int32CodecStringImpl extends AbstractIntegerStringCodec<Integer, IntegerTypeDefinition> implements
309 protected Int32CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
310 super(typeDef, Integer.class);
314 public Integer deserialize(final String stringRepresentation, final int base) {
315 return Integer.valueOf(stringRepresentation, base);
319 public String serialize(final Integer data) {
320 return data == null ? "" : data.toString();
324 public static class Int64CodecStringImpl extends AbstractIntegerStringCodec<Long, IntegerTypeDefinition> implements
327 protected Int64CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
328 super(typeDef, Long.class);
332 public Long deserialize(final String stringRepresentation, final int base) {
333 return Long.valueOf(stringRepresentation, base);
337 public String serialize(final Long data) {
338 return data == null ? "" : data.toString();
342 public static class Int8CodecStringImpl extends AbstractIntegerStringCodec<Byte, IntegerTypeDefinition> implements
345 protected Int8CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
346 super(typeDef, Byte.class);
350 public Byte deserialize(final String stringRepresentation, final int base) {
351 return Byte.valueOf(stringRepresentation, base);
355 public String serialize(final Byte data) {
356 return data == null ? "" : data.toString();
360 public static class EmptyCodecStringImpl extends TypeDefinitionAwareCodec<Void, EmptyTypeDefinition> implements
363 protected EmptyCodecStringImpl(final Optional<EmptyTypeDefinition> typeDef) {
364 super(typeDef, Void.class);
368 public String serialize(final Void data) {
373 public Void deserialize(final String stringRepresentation) {
374 Preconditions.checkArgument( Strings.isNullOrEmpty( stringRepresentation ),
375 "The value must be empty" );
380 public static final class BinaryCodecStringImpl extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
381 implements BinaryCodec<String> {
383 protected BinaryCodecStringImpl(final Optional<BinaryTypeDefinition> typeDef) {
384 super(typeDef, byte[].class);
388 public String serialize(final byte[] data) {
389 return data == null ? "" : BaseEncoding.base64().encode(data);
393 public byte[] deserialize(final String stringRepresentation) {
394 return stringRepresentation == null ? null : DatatypeConverter.parseBase64Binary(stringRepresentation);
398 public static final class BitsCodecStringImpl extends TypeDefinitionAwareCodec<Set<String>, BitsTypeDefinition>
399 implements BitsCodec<String> {
401 public static final Joiner JOINER = Joiner.on(" ").skipNulls();
402 public static final Splitter SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
404 @SuppressWarnings("unchecked")
405 protected BitsCodecStringImpl(final Optional<BitsTypeDefinition> typeDef) {
406 super(typeDef, (Class<Set<String>>) ((Class<?>) Set.class));
410 public String serialize(final Set<String> data) {
411 return data == null ? "" : JOINER.join(data);
415 public Set<String> deserialize(final String stringRepresentation) {
416 if (stringRepresentation == null) {
417 return ImmutableSet.of();
420 final Iterable<String> strings = SPLITTER.split(stringRepresentation);
422 if( getTypeDefinition().isPresent() ) {
423 final Set<String> allowedNames = Sets.newHashSet();
424 for( final BitsTypeDefinition.Bit bit: getTypeDefinition().get().getBits() ) {
425 allowedNames.add( bit.getName() );
428 for( final String bit: strings ) {
429 if( !allowedNames.contains( bit ) ) {
430 throw new IllegalArgumentException(
431 "Invalid value \"" + bit + "\" for bits type. Allowed values are: " +
437 return ImmutableSet.copyOf(strings);
441 public static class EnumCodecStringImpl extends TypeDefinitionAwareCodec<String, EnumTypeDefinition> implements
444 protected EnumCodecStringImpl(final Optional<EnumTypeDefinition> typeDef) {
445 super(typeDef, String.class);
449 public String deserialize(final String stringRepresentation) {
450 if( getTypeDefinition().isPresent() ) {
451 final Set<String> allowedNames = Sets.newHashSet();
452 for( final EnumPair pair: getTypeDefinition().get().getValues() ) {
453 allowedNames.add( pair.getName() );
456 if( !allowedNames.contains( stringRepresentation ) ) {
457 throw new IllegalArgumentException(
458 "Invalid value \"" + stringRepresentation + "\" for enum type. Allowed values are: " +
463 return stringRepresentation;
467 public String serialize(final String data) {
468 return data == null ? "" : data;
472 public static class DecimalCodecStringImpl extends TypeDefinitionAwareCodec<BigDecimal, DecimalTypeDefinition>
473 implements DecimalCodec<String> {
475 protected DecimalCodecStringImpl(final Optional<DecimalTypeDefinition> typeDef) {
476 super(typeDef, BigDecimal.class);
480 public String serialize(final BigDecimal data) {
481 return data == null ? "" : data.toString();
485 public BigDecimal deserialize(final String stringRepresentation) {
486 Preconditions.checkArgument( stringRepresentation != null , "Input cannot be null" );
487 return new BigDecimal(stringRepresentation);
491 public static class UnionCodecStringImpl extends TypeDefinitionAwareCodec<Object, UnionTypeDefinition> implements
494 protected UnionCodecStringImpl(final Optional<UnionTypeDefinition> typeDef) {
495 super(typeDef, Object.class);
499 public String serialize(final Object data) {
500 return data == null ? "" : data.toString();
504 public Object deserialize(final String stringRepresentation) {
505 if( getTypeDefinition().isPresent() ) {
506 boolean valid = false;
507 for( final TypeDefinition<?> type: getTypeDefinition().get().getTypes() ) {
508 final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwareCodec = from( type );
509 if( typeAwareCodec == null ) {
510 // This is a type for which we have no codec (eg identity ref) so we'll say it's valid
511 // but we'll continue in case there's another type for which we do have a codec.
517 typeAwareCodec.deserialize( stringRepresentation );
521 catch( final Exception e ) {
522 // invalid - try the next union type.
527 throw new IllegalArgumentException(
528 "Invalid value \"" + stringRepresentation + "\" for union type." );
532 return stringRepresentation;