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 com.google.common.annotations.VisibleForTesting;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Collections;
15 import java.util.Map.Entry;
16 import java.util.Optional;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.stream.Stream;
19 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
20 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ConvertorData;
21 import org.opendaylight.yangtools.yang.binding.DataContainer;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
26 * Manages various convertors and allows to use them all in one generic way.
28 public class ConvertorManager implements ConvertorExecutor, ConvertorRegistrator {
29 private static final Logger LOG = LoggerFactory.getLogger(ConvertorManager.class);
31 // Cache, that holds all registered convertors, but they can have multiple keys,
32 // based on instanceof checks in the convert method
33 private Map<Short, Map<Class<?>, Convertor<?, ?, ? extends ConvertorData>>> convertors;
36 * Create new instance of Convertor Manager.
38 * @param supportedVersions supported versions
40 public ConvertorManager(final Short... supportedVersions) {
41 final Stream<Short> stream = Arrays.stream(supportedVersions);
43 if (supportedVersions.length == 1) {
44 final Optional<Short> versionOptional = stream.findFirst();
45 versionOptional.ifPresent(version -> convertors =
46 Collections.singletonMap(version, new ConcurrentHashMap<>()));
48 convertors = new ConcurrentHashMap<>();
49 stream.forEach(version -> convertors.putIfAbsent(version, new ConcurrentHashMap<>()));
54 public ConvertorManager registerConvertor(final short version,
55 final Convertor<?, ?, ? extends ConvertorData> convertor) {
56 final Map<Class<?>, Convertor<?, ?, ? extends ConvertorData>> convertorsForVersion =
57 convertors.get(version);
59 if (convertorsForVersion != null) {
60 for (final Class<?> type : convertor.getTypes()) {
61 final Convertor<?, ?, ? extends ConvertorData> result = convertorsForVersion.get(type);
64 convertor.setConvertorExecutor(this);
65 convertorsForVersion.put(type, convertor);
66 LOG.debug("{} for version {} is now converted by {}", type, version, convertor);
68 LOG.warn("{} for version {} have already registered convertor", type, version);
72 LOG.warn("{} do not supports version {}", this, version);
79 @SuppressWarnings("unchecked")
80 public <F, T, D extends ConvertorData> Optional<T> convert(final F source, final D data) {
81 Optional<T> result = Optional.empty();
84 LOG.trace("Cannot extract type from null source");
88 final Class<?> type = source instanceof DataContainer ? ((DataContainer) source).implementedInterface()
92 LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source);
96 return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source, data));
100 @SuppressWarnings("unchecked")
101 public <F, T, D extends ConvertorData> Optional<T> convert(final Collection<F> source, final D data) {
102 Optional<T> result = Optional.empty();
104 if (source == null) {
105 LOG.trace("Cannot extract type from null source");
109 final Optional<F> firstOptional = source.stream().findFirst();
111 if (!firstOptional.isPresent()) {
112 LOG.trace("Cannot extract type from empty collection");
116 final F first = firstOptional.get();
118 final Class<?> type = first instanceof DataContainer ? ((DataContainer) first).implementedInterface()
122 LOG.warn("Cannot extract type from {}, because implementedInterface() returns null", source);
126 return findConvertor(data.getVersion(), type).map(convertor -> (T)convertor.convert(source, data));
130 * Last resort. If we do not already have convertor registered,
131 * we will perform some costly operations and try to find if we
132 * can convert input using any of already registered convertors
133 * @param type input type
134 * @return found convertor
137 Optional<Convertor> findConvertor(final short version, final Class<?> type) {
138 final Map<Class<?>, Convertor<?, ?, ? extends ConvertorData>> convertorsForVersion =
139 convertors.get(version);
141 Optional<Convertor> convertor = Optional.empty();
143 if (convertorsForVersion != null) {
144 convertor = Optional.ofNullable(convertorsForVersion.get(type));
146 if (!convertor.isPresent()) {
147 for (Entry<Class<?>, Convertor<?, ?, ? extends ConvertorData>> entry :
148 convertorsForVersion.entrySet()) {
149 final Class<?> convertorType = entry.getKey();
150 if (type.isAssignableFrom(convertorType)) {
151 final Convertor<?, ?, ? extends ConvertorData> foundConvertor = entry.getValue();
152 convertor = Optional.ofNullable(foundConvertor);
154 if (convertor.isPresent()) {
155 convertorsForVersion.put(type, foundConvertor);
156 LOG.warn("{} for version {} is now converted by {} using last resort method",
157 type, version, foundConvertor);
163 if (!convertor.isPresent()) {
164 LOG.warn("Convertor for {} for version {} not found", type, version);
168 LOG.warn("{} do not supports version {}", this, version);