X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=openflowplugin%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fopenflow%2Fmd%2Fcore%2Fsal%2Fconvertor%2FConvertorManager.java;h=42c6af9f7b0b09e50a14afcff005a6a508d33fe4;hb=05f8db12159673d0e0a95642fe86e62c14b7dc7b;hp=882c4c550f4ffb9cb9d1ef8f0070d9a075b4f060;hpb=e9855fc96cb894b79463b1e3d20e5f44e06e9a96;p=openflowplugin.git diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/convertor/ConvertorManager.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/convertor/ConvertorManager.java index 882c4c550f..42c6af9f7b 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/convertor/ConvertorManager.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/convertor/ConvertorManager.java @@ -5,223 +5,199 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor; -import java.util.ArrayList; +import com.google.common.annotations.VisibleForTesting; +import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; +import java.util.Collections; import java.util.Map; -import java.util.Objects; +import java.util.Map.Entry; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ConvertorData; -import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ParametrizedConvertor; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Manages various convertors and allows to use them all in one generic way + * Manages various convertors and allows to use them all in one generic way. */ -public class ConvertorManager { +public class ConvertorManager implements ConvertorExecutor, ConvertorRegistrator { private static final Logger LOG = LoggerFactory.getLogger(ConvertorManager.class); - private static ConvertorManager INSTANCE; - - static { - INSTANCE = new ConvertorManager(); - // All convertors are registered here - INSTANCE.registerConvertor(new TableFeaturesConvertor()); - INSTANCE.registerConvertor(new TableFeaturesResponseConvertor()); - INSTANCE.registerConvertor(new MeterConvertor()); - } - - // Actual convertor keys - private List> convertorKeys = new ArrayList<>(); - private List> parametrizedConvertorKeys = new ArrayList<>(); // Cache, that holds all registered convertors, but they can have multiple keys, // based on instanceof checks in the convert method - private Map, Convertor> convertors = new HashMap<>(); - private Map, ParametrizedConvertor> parametrizedConvertors = new HashMap<>(); - - private ConvertorManager() { - // Hiding implicit constructor - } - - /** - * Gets instance of Convertor Manager. - * - * @return the instance - */ - public static ConvertorManager getInstance() { - return INSTANCE; - } + private Map, Convertor>> convertors; /** - * Register convertor. + * Create new instance of Convertor Manager. * - * @param convertor the convertor - * @return if registration was successful + * @param supportedVersions supported versions */ - public boolean registerConvertor(final Convertor convertor) { - final Class type = convertor.getType(); - - if (convertors.containsKey(type)) { - LOG.warn("Convertor for type {} is already registered", type); - return false; + public ConvertorManager(final Short... supportedVersions) { + final Stream stream = Arrays.stream(supportedVersions); + + if (supportedVersions.length == 1) { + final Optional versionOptional = stream.findFirst(); + versionOptional.ifPresent(version -> convertors = + Collections.singletonMap(version, new ConcurrentHashMap<>())); + } else { + convertors = new ConcurrentHashMap<>(); + stream.forEach(version -> convertors.putIfAbsent(version, new ConcurrentHashMap<>())); } - - convertorKeys.add(type); - convertors.put(type, convertor); - LOG.debug("{} is now converted by {}", type, convertor); - return true; } - /** - * Register convertor. - * - * @param convertor the convertor - * @return if registration was successful - */ - public boolean registerConvertor(final ParametrizedConvertor convertor) { - final Class type = convertor.getType(); - - if (parametrizedConvertors.containsKey(type)) { - LOG.warn("Convertor for type {} is already registered", type); - return false; + @Override + public ConvertorManager registerConvertor(final short version, + final Convertor convertor) { + final Map, Convertor> convertorsForVersion = + convertors.get(version); + + if (convertorsForVersion != null) { + for (final Class type : convertor.getTypes()) { + final Convertor result = convertorsForVersion.get(type); + + if (result == null) { + convertor.setConvertorExecutor(this); + convertorsForVersion.put(type, convertor); + LOG.debug("{} for version {} is now converted by {}", type, version, convertor); + } else { + LOG.warn("{} for version {} have already registered convertor", type, version); + } + } + } else { + LOG.warn("{} do not supports version {}", this, version); } - parametrizedConvertorKeys.add(type); - parametrizedConvertors.put(type, convertor); - LOG.debug("{} is now converted by {}", type, convertor); - return true; + return this; } - /** - * Lookup and use convertor by specified type, then converts source and returns converted result - * - * @param the source type - * @param the result type - * @param source the source - * @return the result (can be empty, if no convertor was found) - */ + @Override @SuppressWarnings("unchecked") - public Optional convert(final FROM source) { - if (Objects.isNull(source)) { - LOG.trace("Cannot convert source, because it is null"); - return Optional.empty(); + public Optional convert(final F source, final D data) { + Optional result = Optional.empty(); + + if (source == null) { + LOG.trace("Cannot extract type from null source"); + return result; } - Class type = source.getClass(); + final Class type = source instanceof DataContainer ? ((DataContainer) source).implementedInterface() + : source.getClass(); - if (source instanceof Collection) { - final Iterator it = ((Collection) source).iterator(); - Object next = null; + if (type == null) { + LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source); + return result; + } - if (it.hasNext()) { - next = it.next(); - } + return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source, data)); + } - if (Objects.isNull(next)) { - LOG.trace("Cannot convert {}, because it is empty collection", type); - return Optional.empty(); - } + @Override + @SuppressWarnings("unchecked") + public Optional convert(final Map source, final D data) { + Optional result = Optional.empty(); - type = next.getClass(); + if (source == null) { + LOG.trace("Cannot extract type from null source"); + return result; } - Convertor convertor = null; + final Optional firstOptional = source.values().stream().findFirst(); - if (!convertors.containsKey(type)) { - boolean found = false; + if (!firstOptional.isPresent()) { + LOG.trace("Cannot extract type from empty collection"); + return result; + } - for (Class key : convertorKeys) { - if (key.isAssignableFrom(type)) { - convertor = convertors.get(key); - convertors.put(type, convertor); - LOG.debug("{} is now converted by {}", type, convertor); - found = true; - break; - } - } + final F first = firstOptional.get(); - if (!found) { - LOG.error("Convertor for {} not found", type); - return Optional.empty(); - } - } + final Class type = first instanceof DataContainer ? ((DataContainer) first).implementedInterface() + : first.getClass(); - if (Objects.isNull(convertor)) { - convertor = convertors.get(type); + if (type == null) { + LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source); + return result; } - final Object result = convertor.convert(source); - return Optional.of((TO) result); + return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source.values(), data)); } - /** - * Lookup and use convertor by specified type, then converts source and returns converted result - * - * @param the source type - * @param the result type - * @param the data type - * @param source the source - * @param data convertor data - * @return the result (can be empty, if no convertor was found) - */ + @Override @SuppressWarnings("unchecked") - public Optional convert(final FROM source, final DATA data) { - if (Objects.isNull(source)) { - LOG.trace("Cannot convert source, because it is null"); - return Optional.empty(); + public Optional convert(final Collection source, final D data) { + Optional result = Optional.empty(); + + if (source == null) { + LOG.trace("Cannot extract type from null source"); + return result; } - Class type = source.getClass(); + final Optional firstOptional = source.stream().findFirst(); - if (source instanceof Collection) { - final Iterator it = ((Collection) source).iterator(); - Object next = null; + if (!firstOptional.isPresent()) { + LOG.trace("Cannot extract type from empty collection"); + return result; + } - if (it.hasNext()) { - next = it.next(); - } + final F first = firstOptional.get(); - if (Objects.isNull(next)) { - LOG.trace("Cannot convert {}, because it is empty collection", type); - return Optional.empty(); - } + final Class type = first instanceof DataContainer ? ((DataContainer) first).implementedInterface() + : first.getClass(); - type = next.getClass(); + if (type == null) { + LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source); + return result; } - ParametrizedConvertor convertor = null; - - if (!parametrizedConvertors.containsKey(type)) { - boolean found = false; + return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source, data)); + } - for (Class key : parametrizedConvertorKeys) { - if (key.isAssignableFrom(type)) { - convertor = parametrizedConvertors.get(key); - parametrizedConvertors.put(type, convertor); - LOG.debug("{} is now converted by {}", type, convertor); - found = true; - break; + /** + * Last resort. If we do not already have convertor registered, + * we will perform some costly operations and try to find if we + * can convert input using any of already registered convertors + * @param type input type + * @return found convertor + */ + @VisibleForTesting + Optional findConvertor(final short version, final Class type) { + final Map, Convertor> convertorsForVersion = + convertors.get(version); + + Optional convertor = Optional.empty(); + + if (convertorsForVersion != null) { + convertor = Optional.ofNullable(convertorsForVersion.get(type)); + + if (!convertor.isPresent()) { + for (Entry, Convertor> entry : + convertorsForVersion.entrySet()) { + final Class convertorType = entry.getKey(); + if (type.isAssignableFrom(convertorType)) { + final Convertor foundConvertor = entry.getValue(); + convertor = Optional.ofNullable(foundConvertor); + + if (convertor.isPresent()) { + convertorsForVersion.put(type, foundConvertor); + LOG.warn("{} for version {} is now converted by {} using last resort method", + type, version, foundConvertor); + break; + } + } } - } - if (!found) { - LOG.error("Convertor for {} not found", type); - return Optional.empty(); + if (!convertor.isPresent()) { + LOG.warn("Convertor for {} for version {} not found", type, version); + } } + } else { + LOG.warn("{} do not supports version {}", this, version); } - if (Objects.isNull(convertor)) { - convertor = parametrizedConvertors.get(type); - } - - final Object result = convertor.convert(source, data); - return Optional.of((TO) result); + return convertor; } -} \ No newline at end of file +}