2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.VisibleForTesting;
13 import java.util.Arrays;
14 import java.util.Collection;
16 import java.util.Map.Entry;
17 import java.util.Optional;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.stream.Stream;
20 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
21 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ConvertorData;
22 import org.opendaylight.yangtools.yang.binding.DataContainer;
23 import org.opendaylight.yangtools.yang.common.Uint8;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * Manages various convertors and allows to use them all in one generic way.
30 public class ConvertorManager implements ConvertorExecutor, ConvertorRegistrator {
31 private static final Logger LOG = LoggerFactory.getLogger(ConvertorManager.class);
33 // Cache, that holds all registered convertors, but they can have multiple keys,
34 // based on instanceof checks in the convert method
35 private Map<Uint8, Map<Class<?>, Convertor<?, ?, ? extends ConvertorData>>> convertors;
38 * Create new instance of Convertor Manager.
40 * @param supportedVersions supported versions
42 public ConvertorManager(final Uint8... supportedVersions) {
43 final Stream<Uint8> stream = Arrays.stream(supportedVersions);
45 if (supportedVersions.length == 1) {
46 final Optional<Uint8> versionOptional = stream.findFirst();
47 versionOptional.ifPresent(version -> convertors = Map.of(version, new ConcurrentHashMap<>()));
49 convertors = new ConcurrentHashMap<>();
50 stream.forEach(version -> convertors.putIfAbsent(version, new ConcurrentHashMap<>()));
55 public ConvertorManager registerConvertor(final Uint8 version,
56 final Convertor<?, ?, ? extends ConvertorData> convertor) {
57 final Map<Class<?>, Convertor<?, ?, ? extends ConvertorData>> convertorsForVersion =
58 convertors.get(requireNonNull(version));
60 if (convertorsForVersion != null) {
61 for (final Class<?> type : convertor.getTypes()) {
62 final Convertor<?, ?, ? extends ConvertorData> result = convertorsForVersion.get(type);
65 convertor.setConvertorExecutor(this);
66 convertorsForVersion.put(type, convertor);
67 LOG.debug("{} for version {} is now converted by {}", type, version, convertor);
69 LOG.warn("{} for version {} have already registered convertor", type, version);
73 LOG.warn("{} do not supports version {}", this, version);
80 @SuppressWarnings("unchecked")
81 public <F, T, D extends ConvertorData> Optional<T> convert(final F source, final D data) {
82 Optional<T> result = Optional.empty();
85 LOG.trace("Cannot extract type from null source");
89 final Class<?> type = source instanceof DataContainer ? ((DataContainer) source).implementedInterface()
93 LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source);
97 return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source, data));
101 @SuppressWarnings("unchecked")
102 public <K, F, T, D extends ConvertorData> Optional<T> convert(final Map<K, F> source, final D data) {
103 Optional<T> result = Optional.empty();
105 if (source == null) {
106 LOG.trace("Cannot extract type from null source");
110 final Optional<F> firstOptional = source.values().stream().findFirst();
112 if (!firstOptional.isPresent()) {
113 LOG.trace("Cannot extract type from empty collection");
117 final F first = firstOptional.get();
119 final Class<?> type = first instanceof DataContainer ? ((DataContainer) first).implementedInterface()
123 LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source);
127 return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source.values(), data));
131 @SuppressWarnings("unchecked")
132 public <F, T, D extends ConvertorData> Optional<T> convert(final Collection<F> source, final D data) {
133 Optional<T> result = Optional.empty();
135 if (source == null) {
136 LOG.trace("Cannot extract type from null source");
140 final Optional<F> firstOptional = source.stream().findFirst();
142 if (!firstOptional.isPresent()) {
143 LOG.trace("Cannot extract type from empty collection");
147 final F first = firstOptional.get();
149 final Class<?> type = first instanceof DataContainer ? ((DataContainer) first).implementedInterface()
153 LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source);
157 return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source, data));
161 * Last resort. If we do not already have convertor registered,
162 * we will perform some costly operations and try to find if we
163 * can convert input using any of already registered convertors
164 * @param type input type
165 * @return found convertor
168 Optional<Convertor> findConvertor(final Uint8 version, final Class<?> type) {
169 final Map<Class<?>, Convertor<?, ?, ? extends ConvertorData>> convertorsForVersion =
170 convertors.get(requireNonNull(version));
172 Optional<Convertor> convertor = Optional.empty();
174 if (convertorsForVersion != null) {
175 convertor = Optional.ofNullable(convertorsForVersion.get(type));
177 if (!convertor.isPresent()) {
178 for (Entry<Class<?>, Convertor<?, ?, ? extends ConvertorData>> entry :
179 convertorsForVersion.entrySet()) {
180 final Class<?> convertorType = entry.getKey();
181 if (type.isAssignableFrom(convertorType)) {
182 final Convertor<?, ?, ? extends ConvertorData> foundConvertor = entry.getValue();
183 convertor = Optional.ofNullable(foundConvertor);
185 if (convertor.isPresent()) {
186 convertorsForVersion.put(type, foundConvertor);
187 LOG.warn("{} for version {} is now converted by {} using last resort method",
188 type, version, foundConvertor);
194 if (!convertor.isPresent()) {
195 LOG.warn("Convertor for {} for version {} not found", type, version);
199 LOG.warn("{} do not supports version {}", this, version);