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=34291789bd0655edf2d0005b939ec561a69aa73b;hb=f7b6593eaad290c8c1cbd592e9972729a9a953b8;hp=ef84bd6807057ff1af6be4131214ee4158debade;hpb=9c30b963448f71f90d1118a5ad2d55829e1fe451;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 ef84bd6807..34291789bd 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,221 +5,197 @@ * 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 static java.util.Objects.requireNonNull; + +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.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.opendaylight.yangtools.yang.common.Uint8; 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()); - } - - // 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 - } + private Map, Convertor>> convertors; /** - * Gets instance of Convertor Manager. + * Create new instance of Convertor Manager. * - * @return the instance + * @param supportedVersions supported versions */ - public static ConvertorManager getInstance() { - return INSTANCE; - } - - /** - * Register convertor. - * - * @param convertor the convertor - * @return if registration was successful - */ - 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 Uint8... supportedVersions) { + final Stream stream = Arrays.stream(supportedVersions); + + if (supportedVersions.length == 1) { + final Optional versionOptional = stream.findFirst(); + versionOptional.ifPresent(version -> convertors = Map.of(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 Uint8 version, + final Convertor convertor) { + final Map, Convertor> convertorsForVersion = + convertors.get(requireNonNull(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 (firstOptional.isEmpty()) { + LOG.trace("Cannot extract type from empty collection"); + return result; + } - if (!convertors.containsKey(type)) { - boolean found = false; + final F first = firstOptional.orElseThrow(); - 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 Class type = first instanceof DataContainer dataContainer ? dataContainer.implementedInterface() + : first.getClass(); - if (!found) { - LOG.error("Convertor for {} not found", type); - return Optional.empty(); - } + if (type == null) { + LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source); + return result; } - if (Objects.isNull(convertor)) { - convertor = convertors.get(type); - } - - 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(); - Class type = source.getClass(); + if (source == null) { + LOG.trace("Cannot extract type from null source"); + return result; + } - if (source instanceof Collection) { - final Iterator it = ((Collection) source).iterator(); - Object next = null; + final Optional firstOptional = source.stream().findFirst(); + if (firstOptional.isEmpty()) { + LOG.trace("Cannot extract type from empty collection"); + return result; + } - if (it.hasNext()) { - next = it.next(); - } + final F first = firstOptional.orElseThrow(); + final Class type = first instanceof DataContainer dataContainer ? dataContainer.implementedInterface() + : first.getClass(); - if (Objects.isNull(next)) { - LOG.trace("Cannot convert {}, because it is empty collection", type); - return Optional.empty(); - } - - 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 Uint8 version, final Class type) { + final Map, Convertor> convertorsForVersion = + convertors.get(requireNonNull(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 +}