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 com.google.common.base.Joiner;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Splitter;
14 import com.google.common.base.Strings;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Sets;
17 import com.google.common.io.BaseEncoding;
18 import java.math.BigDecimal;
20 import javax.xml.bind.DatatypeConverter;
21 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
22 import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
23 import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
24 import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec;
25 import org.opendaylight.yangtools.yang.data.api.codec.EmptyCodec;
26 import org.opendaylight.yangtools.yang.data.api.codec.EnumCodec;
27 import org.opendaylight.yangtools.yang.data.api.codec.StringCodec;
28 import org.opendaylight.yangtools.yang.data.api.codec.UnionCodec;
29 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
33 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
34 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
35 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
37 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
38 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
39 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
41 import org.opendaylight.yangtools.yang.model.util.DerivedType;
43 public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
47 private final Optional<T> typeDefinition;
48 private final Class<J> inputClass;
52 private static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
53 Optional.<BinaryTypeDefinition> absent());
55 private static final BooleanCodecStringImpl BOOLEAN_DEFAULT_CODEC = new BooleanCodecStringImpl(
56 Optional.<BooleanTypeDefinition> absent());
58 private static final DecimalCodecStringImpl DECIMAL64_DEFAULT_CODEC = new DecimalCodecStringImpl(
59 Optional.<DecimalTypeDefinition> absent());
61 private static final EmptyCodecStringImpl EMPTY_DEFAULT_CODEC = new EmptyCodecStringImpl(
62 Optional.<EmptyTypeDefinition> absent());
64 private static final StringCodecStringImpl STRING_DEFAULT_CODEC = new StringCodecStringImpl(
65 Optional.<StringTypeDefinition> absent());
68 public Class<J> getInputClass() {
72 protected TypeDefinitionAwareCodec(final Optional<T> typeDefinition, final Class<J> outputClass) {
73 Preconditions.checkArgument(outputClass != null, "Output class must be specified.");
74 this.typeDefinition = typeDefinition;
75 this.inputClass = outputClass;
78 public Optional<T> getTypeDefinition() {
79 return typeDefinition;
82 @SuppressWarnings({ "rawtypes", "unchecked" })
83 public static final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> from(final TypeDefinition typeDefinition) {
84 return fromType(typeDefinition);
87 @SuppressWarnings("unchecked")
88 public static final <T extends TypeDefinition<T>> TypeDefinitionAwareCodec<?, T> fromType(final T typeDefinition) {
89 final T normalizedType = (T) DerivedType.from(typeDefinition);
90 @SuppressWarnings("rawtypes")
91 TypeDefinitionAwareCodec codec = null;
93 if (normalizedType instanceof BinaryTypeDefinition) {
94 codec = BINARY_DEFAULT_CODEC;
95 } else if (normalizedType instanceof BitsTypeDefinition) {
96 codec = new BitsCodecStringImpl( Optional.of( (BitsTypeDefinition)normalizedType ) );
97 } else if (normalizedType instanceof BooleanTypeDefinition) {
98 codec = BOOLEAN_DEFAULT_CODEC;
99 } else if (normalizedType instanceof DecimalTypeDefinition) {
100 codec = DECIMAL64_DEFAULT_CODEC;
101 } else if (normalizedType instanceof EmptyTypeDefinition) {
102 codec = EMPTY_DEFAULT_CODEC;
103 } else if (normalizedType instanceof EnumTypeDefinition) {
104 codec = new EnumCodecStringImpl( Optional.of( (EnumTypeDefinition)normalizedType ) );
105 } else if (normalizedType instanceof IntegerTypeDefinition) {
106 codec = AbstractIntegerStringCodec.from((IntegerTypeDefinition) normalizedType);
107 } else if (normalizedType instanceof StringTypeDefinition) {
108 codec = STRING_DEFAULT_CODEC;
109 } else if (normalizedType instanceof UnionTypeDefinition) {
110 codec = new UnionCodecStringImpl( Optional.of( (UnionTypeDefinition)normalizedType ) );
111 } else if (normalizedType instanceof UnsignedIntegerTypeDefinition) {
112 codec = AbstractIntegerStringCodec.from((UnsignedIntegerTypeDefinition) normalizedType);
117 public static class BooleanCodecStringImpl extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
118 implements BooleanCodec<String> {
120 protected BooleanCodecStringImpl(final Optional<BooleanTypeDefinition> typeDef) {
121 super(typeDef, Boolean.class);
125 public String serialize(final Boolean data) {
126 return data == null ? "" : data.toString();
130 public Boolean deserialize(final String stringRepresentation) {
131 return Boolean.valueOf(stringRepresentation);
136 public static class Uint8CodecStringImpl extends Uint8StringCodec {
138 protected Uint8CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
144 public static class Uint16CodecStringImpl extends Uint16StringCodec {
145 protected Uint16CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
151 public static class Uint32CodecStringImpl extends Uint32StringCodec {
153 protected Uint32CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
160 public static class Uint64CodecStringImpl extends Uint64StringCodec {
162 protected Uint64CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
168 public static class StringCodecStringImpl extends TypeDefinitionAwareCodec<String, StringTypeDefinition> implements
169 StringCodec<String> {
171 protected StringCodecStringImpl(final Optional<StringTypeDefinition> typeDef) {
172 super(typeDef, String.class);
176 public String deserialize(final String stringRepresentation) {
177 return stringRepresentation == null ? "" : stringRepresentation;
181 public String serialize(final String data) {
182 return data == null ? "" : data;
187 public static class Int16CodecStringImpl extends Int16StringCodec {
189 protected Int16CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
196 public static class Int32CodecStringImpl extends Int32StringCodec {
198 protected Int32CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
205 public static class Int64CodecStringImpl extends Int64StringCodec {
207 protected Int64CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
214 public static class Int8CodecStringImpl extends Int8StringCodec {
216 protected Int8CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
222 public static class EmptyCodecStringImpl extends TypeDefinitionAwareCodec<Void, EmptyTypeDefinition> implements
225 protected EmptyCodecStringImpl(final Optional<EmptyTypeDefinition> typeDef) {
226 super(typeDef, Void.class);
230 public String serialize(final Void data) {
235 public Void deserialize(final String stringRepresentation) {
236 Preconditions.checkArgument( Strings.isNullOrEmpty( stringRepresentation ),
237 "The value must be empty" );
242 public static final class BinaryCodecStringImpl extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
243 implements BinaryCodec<String> {
245 protected BinaryCodecStringImpl(final Optional<BinaryTypeDefinition> typeDef) {
246 super(typeDef, byte[].class);
250 public String serialize(final byte[] data) {
251 return data == null ? "" : BaseEncoding.base64().encode(data);
255 public byte[] deserialize(final String stringRepresentation) {
256 return stringRepresentation == null ? null : DatatypeConverter.parseBase64Binary(stringRepresentation);
260 public static final class BitsCodecStringImpl extends TypeDefinitionAwareCodec<Set<String>, BitsTypeDefinition>
261 implements BitsCodec<String> {
263 public static final Joiner JOINER = Joiner.on(" ").skipNulls();
264 public static final Splitter SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
266 @SuppressWarnings("unchecked")
267 protected BitsCodecStringImpl(final Optional<BitsTypeDefinition> typeDef) {
268 super(typeDef, (Class<Set<String>>) ((Class<?>) Set.class));
272 public String serialize(final Set<String> data) {
273 return data == null ? "" : JOINER.join(data);
277 public Set<String> deserialize(final String stringRepresentation) {
278 if (stringRepresentation == null) {
279 return ImmutableSet.of();
282 final Iterable<String> strings = SPLITTER.split(stringRepresentation);
284 if( getTypeDefinition().isPresent() ) {
285 final Set<String> allowedNames = Sets.newHashSet();
286 for( final BitsTypeDefinition.Bit bit: getTypeDefinition().get().getBits() ) {
287 allowedNames.add( bit.getName() );
290 for( final String bit: strings ) {
291 if( !allowedNames.contains( bit ) ) {
292 throw new IllegalArgumentException(
293 "Invalid value \"" + bit + "\" for bits type. Allowed values are: " +
299 return ImmutableSet.copyOf(strings);
303 public static class EnumCodecStringImpl extends TypeDefinitionAwareCodec<String, EnumTypeDefinition> implements
306 protected EnumCodecStringImpl(final Optional<EnumTypeDefinition> typeDef) {
307 super(typeDef, String.class);
311 public String deserialize(final String stringRepresentation) {
312 if( getTypeDefinition().isPresent() ) {
313 final Set<String> allowedNames = Sets.newHashSet();
314 for( final EnumPair pair: getTypeDefinition().get().getValues() ) {
315 allowedNames.add( pair.getName() );
318 if( !allowedNames.contains( stringRepresentation ) ) {
319 throw new IllegalArgumentException(
320 "Invalid value \"" + stringRepresentation + "\" for enum type. Allowed values are: " +
325 return stringRepresentation;
329 public String serialize(final String data) {
330 return data == null ? "" : data;
334 public static class DecimalCodecStringImpl extends TypeDefinitionAwareCodec<BigDecimal, DecimalTypeDefinition>
335 implements DecimalCodec<String> {
337 protected DecimalCodecStringImpl(final Optional<DecimalTypeDefinition> typeDef) {
338 super(typeDef, BigDecimal.class);
342 public String serialize(final BigDecimal data) {
343 return data == null ? "" : data.toString();
347 public BigDecimal deserialize(final String stringRepresentation) {
348 Preconditions.checkArgument( stringRepresentation != null , "Input cannot be null" );
349 return new BigDecimal(stringRepresentation);
353 public static class UnionCodecStringImpl extends TypeDefinitionAwareCodec<Object, UnionTypeDefinition> implements
356 protected UnionCodecStringImpl(final Optional<UnionTypeDefinition> typeDef) {
357 super(typeDef, Object.class);
361 public String serialize(final Object data) {
362 return data == null ? "" : data.toString();
366 public Object deserialize(final String stringRepresentation) {
367 if( getTypeDefinition().isPresent() ) {
368 boolean valid = false;
369 for( final TypeDefinition<?> type: getTypeDefinition().get().getTypes() ) {
370 final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwareCodec = from( type );
371 if( typeAwareCodec == null ) {
372 // This is a type for which we have no codec (eg identity ref) so we'll say it's valid
373 // but we'll continue in case there's another type for which we do have a codec.
379 typeAwareCodec.deserialize( stringRepresentation );
383 catch( final Exception e ) {
384 // invalid - try the next union type.
389 throw new IllegalArgumentException(
390 "Invalid value \"" + stringRepresentation + "\" for union type." );
394 return stringRepresentation;