Compact BitsCodec
[mdsal.git] / code-generator / binding-data-codec / src / main / java / org / opendaylight / yangtools / binding / data / codec / impl / BitsCodec.java
1 /*
2  * Copyright (c) 2014 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.binding.data.codec.impl;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableSortedMap;
12 import java.lang.reflect.Constructor;
13 import java.lang.reflect.InvocationTargetException;
14 import java.lang.reflect.Method;
15 import java.util.HashSet;
16 import java.util.Map.Entry;
17 import java.util.Set;
18 import java.util.SortedMap;
19 import java.util.TreeMap;
20 import java.util.concurrent.Callable;
21 import org.opendaylight.yangtools.binding.data.codec.impl.ValueTypeCodec.SchemaUnawareCodec;
22 import org.opendaylight.yangtools.yang.binding.BindingMapping;
23 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
25
26 class BitsCodec extends ReflectionBasedCodec implements SchemaUnawareCodec {
27
28     private final ImmutableSortedMap<String, Method> valueGetters;
29     private final Constructor<?> constructor;
30
31     private BitsCodec(final Class<?> typeClass, final SortedMap<String, Method> valueGetters,
32             final Constructor<?> constructor) {
33         super(typeClass);
34         this.valueGetters = ImmutableSortedMap.copyOf(valueGetters);
35         this.constructor = constructor;
36     }
37
38     static Callable<BitsCodec> loader(final Class<?> returnType,
39             final BitsTypeDefinition rootType) {
40         return new Callable<BitsCodec>() {
41
42             @Override
43             public BitsCodec call() throws Exception {
44                 try {
45                     SortedMap<String, Method> valueGetters = new TreeMap<>();
46                     for (Bit bit : rootType.getBits()) {
47                         String bindingName = BindingMapping.getClassName(bit.getName());
48                         Method valueGetter = returnType.getMethod("is" + bindingName);
49                         valueGetters.put(bit.getName(), valueGetter);
50
51                     }
52                     Constructor<?> constructor = null;
53                     for (Constructor<?> cst : returnType.getConstructors()) {
54                         if (cst.getParameterTypes()[0].equals(returnType)) {
55                             continue;
56                         }
57                         constructor = cst;
58                     }
59
60                     return new BitsCodec(returnType, valueGetters, constructor);
61                 } catch (IllegalArgumentException | NoSuchMethodException | SecurityException e) {
62                     throw new IllegalStateException(e);
63                 }
64             }
65         };
66     }
67
68     @Override
69     public Object deserialize(final Object input) {
70         Preconditions.checkArgument(input instanceof Set);
71         @SuppressWarnings("unchecked")
72         Set<String> casted = (Set<String>) input;
73
74         Object args[] = new Object[valueGetters.size()];
75         int currentArg = 0;
76         /*
77          * We can do this walk based on field set
78          * sorted by name, since constructor arguments in
79          * Java Binding are sorted by name.
80          *
81          * This means we will construct correct array
82          * for construction of bits object.
83          */
84         for (String value : valueGetters.keySet()) {
85             args[currentArg++] = casted.contains(value);
86         }
87
88         try {
89             return constructor.newInstance(args);
90         } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
91             throw new IllegalStateException(e);
92         }
93     }
94
95     @Override
96     public Object serialize(final Object input) {
97         Set<String> result = new HashSet<>();
98         for (Entry<String, Method> valueGet : valueGetters.entrySet()) {
99             try {
100                 Boolean value = (Boolean) valueGet.getValue().invoke(input);
101                 if (value) {
102                     result.add(valueGet.getKey());
103                 }
104             } catch (IllegalAccessException | InvocationTargetException e) {
105                 throw new IllegalArgumentException(e);
106             }
107         }
108         return result;
109     }
110 }