a1fa857775319ca249d50484604bf22d16703b23
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / codec / TypeDefinitionAwareCodec.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.impl.codec;
9
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;
18
19 import java.math.BigDecimal;
20 import java.math.BigInteger;
21 import java.util.Set;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
26 import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
27 import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
28 import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec;
29 import org.opendaylight.yangtools.yang.data.api.codec.EmptyCodec;
30 import org.opendaylight.yangtools.yang.data.api.codec.EnumCodec;
31 import org.opendaylight.yangtools.yang.data.api.codec.Int16Codec;
32 import org.opendaylight.yangtools.yang.data.api.codec.Int32Codec;
33 import org.opendaylight.yangtools.yang.data.api.codec.Int64Codec;
34 import org.opendaylight.yangtools.yang.data.api.codec.Int8Codec;
35 import org.opendaylight.yangtools.yang.data.api.codec.StringCodec;
36 import org.opendaylight.yangtools.yang.data.api.codec.Uint16Codec;
37 import org.opendaylight.yangtools.yang.data.api.codec.Uint32Codec;
38 import org.opendaylight.yangtools.yang.data.api.codec.Uint64Codec;
39 import org.opendaylight.yangtools.yang.data.api.codec.Uint8Codec;
40 import org.opendaylight.yangtools.yang.data.api.codec.UnionCodec;
41 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
42 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
43 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
44 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
45 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
46 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
47 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
48 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
49 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
50 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
51 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
52
53 import com.google.common.base.Joiner;
54 import com.google.common.base.Optional;
55 import com.google.common.base.Preconditions;
56 import com.google.common.base.Splitter;
57 import com.google.common.collect.ImmutableSet;
58 import com.google.common.io.BaseEncoding;
59
60 public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
61     
62     private static final Pattern intPattern = Pattern.compile("[+-]?[1-9][0-9]*$");
63     private static final Pattern hexPattern = Pattern.compile("[+-]?0[xX][0-9a-fA-F]+");
64     private static final Pattern octalPattern = Pattern.compile("[+-]?0[1-7][0-7]*$");
65     
66     private final Optional<T> typeDefinition;
67     private final Class<J> inputClass;
68     
69     private static final int provideBase(final String integer) {
70         if (integer == null) {
71             throw new IllegalArgumentException("String representing integer number cannot be NULL!");
72         }
73         
74         if ((integer.length() == 1) && (integer.charAt(0) == '0')) {
75             return 10;
76         }
77         
78         final Matcher intMatcher = intPattern.matcher(integer);
79         if (intMatcher.matches()) {
80             return 10;
81         } else {
82             final Matcher hexMatcher = hexPattern.matcher(integer);
83             if (hexMatcher.matches()) {
84                 return 16;
85             } else {
86                 final Matcher octMatcher = octalPattern.matcher(integer);
87                 if (octMatcher.matches()) {
88                     return 8;
89                 } else {
90                     throw new NumberFormatException("Incorrect lexical representation of Integer value!"
91                             + "The Integer value can be defined as Integer Number, Hexadecimal Number or"
92                             + "Octal Number. The sign vlues are allowed. "
93                             + "Spaces between digits are NOT allowed!");
94                 }
95             }
96         }
97     }
98     
99     private static String normalizeHexadecimal(final String hexInt) {
100         if (hexInt == null) {
101             throw new IllegalArgumentException(
102                     "String representing integer number in Hexadecimal format cannot be NULL!");
103         }
104         final String normalizedString;
105         if (hexInt.contains("x")) {
106             normalizedString = hexInt.replace("x", "");
107         } else if (hexInt.contains("X")) {
108             normalizedString = hexInt.replace("X", "");
109         } else {
110             normalizedString = hexInt;
111         }
112         return normalizedString;
113     }
114     
115     public static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
116             Optional.<BinaryTypeDefinition> absent());
117
118     public static final BitsCodecStringImpl BITS_DEFAULT_CODEC = new BitsCodecStringImpl(
119             Optional.<BitsTypeDefinition> absent());
120
121     public static final BooleanCodecStringImpl BOOLEAN_DEFAULT_CODEC = new BooleanCodecStringImpl(
122             Optional.<BooleanTypeDefinition> absent());
123
124     public static final DecimalCodecStringImpl DECIMAL64_DEFAULT_CODEC = new DecimalCodecStringImpl(
125             Optional.<DecimalTypeDefinition> absent());
126
127     public static final EmptyCodecStringImpl EMPTY_DEFAULT_CODEC = new EmptyCodecStringImpl(
128             Optional.<EmptyTypeDefinition> absent());
129
130     public static final EnumCodecStringImpl ENUMERATION_DEFAULT_CODEC = new EnumCodecStringImpl(
131             Optional.<EnumTypeDefinition> absent());
132
133     public static final Int8CodecStringImpl INT8_DEFAULT_CODEC = new Int8CodecStringImpl(
134             Optional.<IntegerTypeDefinition> absent());
135
136     public static final Int16CodecStringImpl INT16_DEFAULT_CODEC = new Int16CodecStringImpl(
137             Optional.<IntegerTypeDefinition> absent());
138
139     public static final Int32CodecStringImpl INT32_DEFAULT_CODEC = new Int32CodecStringImpl(
140             Optional.<IntegerTypeDefinition> absent());
141
142     public static final Int64CodecStringImpl INT64_DEFAULT_CODEC = new Int64CodecStringImpl(
143             Optional.<IntegerTypeDefinition> absent());
144
145     public static final StringCodecStringImpl STRING_DEFAULT_CODEC = new StringCodecStringImpl(
146             Optional.<StringTypeDefinition> absent());
147
148     public static final Uint8CodecStringImpl UINT8_DEFAULT_CODEC = new Uint8CodecStringImpl(
149             Optional.<UnsignedIntegerTypeDefinition> absent());
150
151     public static final Uint16CodecStringImpl UINT16_DEFAULT_CODEC = new Uint16CodecStringImpl(
152             Optional.<UnsignedIntegerTypeDefinition> absent());
153
154     public static final Uint32CodecStringImpl UINT32_DEFAULT_CODEC = new Uint32CodecStringImpl(
155             Optional.<UnsignedIntegerTypeDefinition> absent());
156
157     public static final Uint64CodecStringImpl UINT64_DEFAULT_CODEC = new Uint64CodecStringImpl(
158             Optional.<UnsignedIntegerTypeDefinition> absent());
159
160     public static final UnionCodecStringImpl UNION_DEFAULT_CODEC = new UnionCodecStringImpl(
161             Optional.<UnionTypeDefinition> absent());
162
163     public Class<J> getInputClass() {
164         return inputClass;
165     }
166
167     protected TypeDefinitionAwareCodec(Optional<T> typeDefinition, Class<J> outputClass) {
168         Preconditions.checkArgument(outputClass != null, "Output class must be specified.");
169         this.typeDefinition = typeDefinition;
170         this.inputClass = outputClass;
171     }
172
173     public Optional<T> getTypeDefinition() {
174         return typeDefinition;
175     }
176
177     @SuppressWarnings({ "rawtypes", "unchecked" })
178     public static final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> from(TypeDefinition typeDefinition) {
179         final TypeDefinitionAwareCodec codec = fromType(typeDefinition);
180         return (TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>>) codec;
181     }
182
183     public static final <T extends TypeDefinition<T>> TypeDefinitionAwareCodec<?, T> fromType(T typeDefinition) {
184         T superType = typeDefinition;
185         while (superType.getBaseType() != null) {
186             superType = superType.getBaseType();
187         }
188
189         @SuppressWarnings("rawtypes")
190         TypeDefinitionAwareCodec codec = null;
191
192         if (superType instanceof BinaryTypeDefinition) {
193             codec = BINARY_DEFAULT_CODEC;
194         } else if (superType instanceof BitsTypeDefinition) {
195             codec = BITS_DEFAULT_CODEC;
196         } else if (superType instanceof BooleanTypeDefinition) {
197             codec = BOOLEAN_DEFAULT_CODEC;
198         } else if (superType instanceof DecimalTypeDefinition) {
199             codec = DECIMAL64_DEFAULT_CODEC;
200         } else if (superType instanceof EmptyTypeDefinition) {
201             codec = EMPTY_DEFAULT_CODEC;
202         } else if (superType instanceof EnumTypeDefinition) {
203             codec = ENUMERATION_DEFAULT_CODEC;
204         } else if (superType instanceof IntegerTypeDefinition) {
205             if (INT8_QNAME.equals(superType.getQName())) {
206                 codec = INT8_DEFAULT_CODEC;
207             } else if (INT16_QNAME.equals(superType.getQName())) {
208                 codec = INT16_DEFAULT_CODEC;
209             } else if (INT32_QNAME.equals(superType.getQName())) {
210                 codec = INT32_DEFAULT_CODEC;
211             } else if (INT64_QNAME.equals(superType.getQName())) {
212                 codec = INT64_DEFAULT_CODEC;
213             }
214         } else if (superType instanceof StringTypeDefinition) {
215             codec = STRING_DEFAULT_CODEC;
216         } else if (superType instanceof UnionTypeDefinition) {
217             codec = UNION_DEFAULT_CODEC;
218         } else if (superType instanceof UnsignedIntegerTypeDefinition) {
219             if (UINT8_QNAME.equals(superType.getQName())) {
220                 codec = UINT8_DEFAULT_CODEC;
221             }
222             if (UINT16_QNAME.equals(superType.getQName())) {
223                 codec = UINT16_DEFAULT_CODEC;
224             }
225             if (UINT32_QNAME.equals(superType.getQName())) {
226                 codec = UINT32_DEFAULT_CODEC;
227             }
228             if (UINT64_QNAME.equals(superType.getQName())) {
229                 codec = UINT64_DEFAULT_CODEC;
230             }
231         }
232         @SuppressWarnings("unchecked")
233         TypeDefinitionAwareCodec<?, T> ret = (TypeDefinitionAwareCodec<?, T>) codec;
234         return ret;
235     }
236
237     public static class BooleanCodecStringImpl extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
238             implements BooleanCodec<String> {
239
240         protected BooleanCodecStringImpl(Optional<BooleanTypeDefinition> typeDef) {
241             super(typeDef, Boolean.class);
242         }
243
244         @Override
245         public String serialize(Boolean data) {
246             return data == null ? "" : data.toString();
247         }
248
249         @Override
250         public Boolean deserialize(String stringRepresentation) {
251             return Boolean.valueOf(stringRepresentation);
252         }
253     };
254
255     public static class Uint8CodecStringImpl extends TypeDefinitionAwareCodec<Short, UnsignedIntegerTypeDefinition>
256             implements Uint8Codec<String> {
257
258         protected Uint8CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
259             super(typeDef, Short.class);
260         }
261
262         @Override
263         public String serialize(Short data) {
264             return data == null ? "" : data.toString();
265         }
266
267         @Override
268         public Short deserialize(String stringRepresentation) {
269             int base = provideBase(stringRepresentation);
270             if (base == 16) {
271                 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
272             }
273             return Short.valueOf(stringRepresentation, base);
274         }
275     };
276
277     public static class Uint16CodecStringImpl extends TypeDefinitionAwareCodec<Integer, UnsignedIntegerTypeDefinition>
278             implements Uint16Codec<String> {
279         protected Uint16CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
280             super(typeDef, Integer.class);
281         }
282
283         @Override
284         public Integer deserialize(String stringRepresentation) {
285             int base = provideBase(stringRepresentation);
286             if (base == 16) {
287                 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
288             }
289             return Integer.valueOf(stringRepresentation, base);
290         }
291
292         @Override
293         public String serialize(Integer data) {
294             return data == null ? "" : data.toString();
295         }
296     };
297
298     public static class Uint32CodecStringImpl extends TypeDefinitionAwareCodec<Long, UnsignedIntegerTypeDefinition>
299             implements Uint32Codec<String> {
300
301         protected Uint32CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
302             super(typeDef, Long.class);
303         }
304
305         @Override
306         public Long deserialize(String stringRepresentation) {
307             int base = provideBase(stringRepresentation);
308             if (base == 16) {
309                 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
310             }
311             return Long.valueOf(stringRepresentation, base);
312         }
313
314         @Override
315         public String serialize(Long data) {
316             return data == null ? "" : data.toString();
317         }
318     };
319
320     public static class Uint64CodecStringImpl extends
321             TypeDefinitionAwareCodec<BigInteger, UnsignedIntegerTypeDefinition> implements Uint64Codec<String> {
322
323         protected Uint64CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
324             super(typeDef, BigInteger.class);
325         }
326
327         @Override
328         public BigInteger deserialize(String stringRepresentation) {
329             int base = provideBase(stringRepresentation);
330             if (base == 16) {
331                 return new BigInteger(normalizeHexadecimal(stringRepresentation), base);
332             }
333             return new BigInteger(stringRepresentation, base);
334         }
335
336         @Override
337         public String serialize(BigInteger data) {
338             return data == null ? "" : data.toString();
339         }
340     };
341
342     public static class StringCodecStringImpl extends TypeDefinitionAwareCodec<String, StringTypeDefinition> implements
343             StringCodec<String> {
344
345         protected StringCodecStringImpl(Optional<StringTypeDefinition> typeDef) {
346             super(typeDef, String.class);
347         }
348
349         @Override
350         public String deserialize(String stringRepresentation) {
351             return stringRepresentation;
352         }
353
354         @Override
355         public String serialize(String data) {
356             return data == null ? "" : data.toString();
357         }
358     };
359
360     public static class Int16CodecStringImpl extends TypeDefinitionAwareCodec<Short, IntegerTypeDefinition> implements
361             Int16Codec<String> {
362
363         protected Int16CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
364             super(typeDef, Short.class);
365         }
366
367         @Override
368         public Short deserialize(String stringRepresentation) {
369             int base = provideBase(stringRepresentation);
370             if (base == 16) {
371                 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
372             }
373             return Short.valueOf(stringRepresentation, base);
374         }
375
376         @Override
377         public String serialize(Short data) {
378             return data == null ? "" : data.toString();
379         }
380     };
381
382     public static class Int32CodecStringImpl extends TypeDefinitionAwareCodec<Integer, IntegerTypeDefinition> implements
383             Int32Codec<String> {
384
385         protected Int32CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
386             super(typeDef, Integer.class);
387         }
388
389         @Override
390         public Integer deserialize(String stringRepresentation) {
391             int base = provideBase(stringRepresentation);
392             if (base == 16) {
393                 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
394             }
395             return Integer.valueOf(stringRepresentation, base);
396         }
397
398         @Override
399         public String serialize(Integer data) {
400             return data == null ? "" : data.toString();
401         }
402     };
403
404     public static class Int64CodecStringImpl extends TypeDefinitionAwareCodec<Long, IntegerTypeDefinition> implements
405             Int64Codec<String> {
406
407         protected Int64CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
408             super(typeDef, Long.class);
409         }
410
411         @Override
412         public Long deserialize(String stringRepresentation) {
413             int base = provideBase(stringRepresentation);
414             if (base == 16) {
415                 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
416             }
417             return Long.valueOf(stringRepresentation, base);
418         }
419
420         @Override
421         public String serialize(Long data) {
422             return data == null ? "" : data.toString();
423         }
424     };
425
426     public static class Int8CodecStringImpl extends TypeDefinitionAwareCodec<Byte, IntegerTypeDefinition> implements
427             Int8Codec<String> {
428
429         protected Int8CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
430             super(typeDef, Byte.class);
431         }
432
433         @Override
434         public Byte deserialize(String stringRepresentation) {
435             int base = provideBase(stringRepresentation);
436             if (base == 16) {
437                 return Byte.valueOf(normalizeHexadecimal(stringRepresentation), base);
438             }
439             return Byte.valueOf(stringRepresentation, base);
440         }
441
442         @Override
443         public String serialize(Byte data) {
444             return data == null ? "" : data.toString();
445         }
446     };
447
448     public static class EmptyCodecStringImpl extends TypeDefinitionAwareCodec<Void, EmptyTypeDefinition> implements
449             EmptyCodec<String> {
450
451         protected EmptyCodecStringImpl(Optional<EmptyTypeDefinition> typeDef) {
452             super(typeDef, Void.class);
453         }
454
455         @Override
456         public String serialize(Void data) {
457             return "";
458         }
459
460         @Override
461         public Void deserialize(String stringRepresentation) {
462             return null;
463         }
464     };
465
466     public static final class BinaryCodecStringImpl extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
467             implements BinaryCodec<String> {
468
469         protected BinaryCodecStringImpl(Optional<BinaryTypeDefinition> typeDef) {
470             super(typeDef, byte[].class);
471         }
472
473         @Override
474         public String serialize(byte[] data) {
475             return data == null ? "" : BaseEncoding.base64().encode(data);
476         }
477
478         @Override
479         public byte[] deserialize(String stringRepresentation) {
480             return BaseEncoding.base64().decode(stringRepresentation);
481         }
482     };
483
484     public static final class BitsCodecStringImpl extends TypeDefinitionAwareCodec<Set<String>, BitsTypeDefinition>
485             implements BitsCodec<String> {
486
487         public static final Joiner JOINER = Joiner.on(" ").skipNulls();
488         public static final Splitter SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
489
490         @SuppressWarnings("unchecked")
491         protected BitsCodecStringImpl(Optional<BitsTypeDefinition> typeDef) {
492             super(typeDef, (Class<Set<String>>) ((Class<?>) Set.class));
493         }
494
495         @Override
496         public String serialize(Set<String> data) {
497             return data == null ? "" : JOINER.join(data);
498         }
499
500         @Override
501         public Set<String> deserialize(String stringRepresentation) {
502             if (stringRepresentation == null)
503                 return ImmutableSet.of();
504             Iterable<String> strings = SPLITTER.split(stringRepresentation);
505             return ImmutableSet.copyOf(strings);
506         }
507     };
508
509     public static class EnumCodecStringImpl extends TypeDefinitionAwareCodec<String, EnumTypeDefinition> implements
510             EnumCodec<String> {
511
512         protected EnumCodecStringImpl(Optional<EnumTypeDefinition> typeDef) {
513             super(typeDef, String.class);
514         }
515
516         @Override
517         public String deserialize(String stringRepresentation) {
518             return stringRepresentation;
519         }
520
521         @Override
522         public String serialize(String data) {
523             return data == null ? "" : data.toString();
524         }
525     };
526
527     public static class DecimalCodecStringImpl extends TypeDefinitionAwareCodec<BigDecimal, DecimalTypeDefinition>
528             implements DecimalCodec<String> {
529
530         protected DecimalCodecStringImpl(Optional<DecimalTypeDefinition> typeDef) {
531             super(typeDef, BigDecimal.class);
532         }
533
534         @Override
535         public String serialize(BigDecimal data) {
536             return data == null ? "" : data.toString();
537         }
538
539         @Override
540         public BigDecimal deserialize(String stringRepresentation) {
541             return new BigDecimal(stringRepresentation);
542         }
543     };
544
545     public static class UnionCodecStringImpl extends TypeDefinitionAwareCodec<String, UnionTypeDefinition> implements
546             UnionCodec<String> {
547
548         protected UnionCodecStringImpl(Optional<UnionTypeDefinition> typeDef) {
549             super(typeDef, String.class);
550         }
551
552         @Override
553         public String serialize(String data) {
554             return data == null ? "" : data;
555         }
556
557         @Override
558         public String deserialize(String stringRepresentation) {
559             return stringRepresentation;
560         }
561     };
562 }