Merge codec contexts caches
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / EnumerationCodec.java
index ebe9c7d5d5c399d2f294a3c6da231138fb61da54..2e16b0c616c0144b0ceee188b6ae47f0d4b90388 100644 (file)
@@ -8,58 +8,73 @@
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.collect.BiMap;
 import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableBiMap.Builder;
+import com.google.common.collect.Maps;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.stream.Collectors;
 import org.opendaylight.mdsal.binding.dom.codec.impl.ValueTypeCodec.SchemaUnawareCodec;
-import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.Enumeration;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 final class EnumerationCodec extends ReflectionBasedCodec implements SchemaUnawareCodec {
-    private final ImmutableBiMap<String, Enum<?>> yangValueToBinding;
+    private static final Logger LOG = LoggerFactory.getLogger(EnumerationCodec.class);
 
-    EnumerationCodec(final Class<? extends Enum<?>> enumeration, final ImmutableBiMap<String, Enum<?>> schema) {
+    private final ImmutableBiMap<String, Enum<?>> nameToEnum;
+
+    EnumerationCodec(final Class<? extends Enum<?>> enumeration, final Map<String, Enum<?>> nameToEnum) {
         super(enumeration);
-        yangValueToBinding = requireNonNull(schema);
+        this.nameToEnum = ImmutableBiMap.copyOf(nameToEnum);
     }
 
-    static Callable<EnumerationCodec> loader(final Class<?> returnType, final EnumTypeDefinition enumSchema) {
+    static Callable<EnumerationCodec> loader(final Class<?> returnType, final EnumTypeDefinition def) {
         checkArgument(Enum.class.isAssignableFrom(returnType));
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        final Class<? extends Enum<?>> enumType = (Class) returnType;
+        @SuppressWarnings("unchecked")
+        final Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) returnType;
         return () -> {
-            final BiMap<String, String> identifierToYang = BindingMapping.mapEnumAssignedNames(
-                enumSchema.getValues().stream().map(EnumPair::getName).collect(Collectors.toList())).inverse();
+            final Map<String, Enum<?>> mapping = Maps.uniqueIndex(Arrays.asList(enumType.getEnumConstants()),
+                value -> {
+                    checkArgument(value instanceof Enumeration,
+                        "Enumeration constant %s.%s is not implementing Enumeration", enumType.getName(), value);
+                    return ((Enumeration) value).getName();
+                });
 
-            final Builder<String, Enum<?>> builder = ImmutableBiMap.builder();
-            for (Enum<?> enumValue : enumType.getEnumConstants()) {
-                final String yangName = identifierToYang.get(enumValue.name());
-                checkState(yangName != null, "Failed to find enumeration constant %s in mapping %s", enumValue,
-                        identifierToYang);
-                builder.put(yangName, enumValue);
+            // Check if mapping is a bijection
+            final Set<String> assignedNames =  def.getValues().stream().map(EnumPair::getName)
+                    .collect(Collectors.toSet());
+            for (String name : assignedNames) {
+                if (!mapping.containsKey(name)) {
+                    LOG.warn("Enumeration {} does not contain assigned name '{}' from {}", enumType, name, def);
+                }
+            }
+            for (String name : mapping.keySet()) {
+                if (!assignedNames.contains(name)) {
+                    LOG.warn("Enumeration {} contains assigned name '{}' not covered by {}", enumType, name, def);
+                }
             }
 
-            return new EnumerationCodec(enumType, builder.build());
+            return new EnumerationCodec(enumType, mapping);
         };
     }
 
     @Override
-    public Object deserialize(final Object input) {
-        Enum<?> value = yangValueToBinding.get(input);
-        checkArgument(value != null, "Invalid enumeration value %s. Valid values are %s", input,
-                yangValueToBinding.keySet());
+    public Enum<?> deserialize(final Object input) {
+        checkArgument(input instanceof String, "Input %s is not a String", input);
+        final Enum<?> value = nameToEnum.get(input);
+        checkArgument(value != null, "Invalid enumeration value %s. Valid values are %s", input, nameToEnum.keySet());
         return value;
     }
 
     @Override
-    public Object serialize(final Object input) {
-        checkArgument(getTypeClass().isInstance(input), "Input must be instance of %s", getTypeClass());
-        return yangValueToBinding.inverse().get(input);
+    public String serialize(final Object input) {
+        checkArgument(getTypeClass().isInstance(input), "Input %s is not a instance of %s", input, getTypeClass());
+        return requireNonNull(nameToEnum.inverse().get(input));
     }
 }
\ No newline at end of file