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
9 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.List;
15 import java.util.Objects;
16 import java.util.Optional;
17 import java.util.concurrent.ConcurrentHashMap;
18 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.ActionConvertor;
19 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.ActionResponseConvertor;
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.openflowplugin.openflow.md.core.sal.convertor.common.ParametrizedConvertor;
23 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.FlowConvertor;
24 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.FlowInstructionResponseConvertor;
25 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.FlowStatsResponseConvertor;
26 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchResponseConvertor;
27 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchV10ResponseConvertor;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * Manages various convertors and allows to use them all in one generic way
34 public class ConvertorManager implements ConvertorRegistrator, ConvertorExecutor {
35 private static final Logger LOG = LoggerFactory.getLogger(ConvertorManager.class);
36 private static ConvertorManager INSTANCE;
39 INSTANCE = new ConvertorManager();
40 // All convertors are registered here
41 INSTANCE.registerConvertor(new TableFeaturesConvertor());
42 INSTANCE.registerConvertor(new TableFeaturesResponseConvertor());
43 INSTANCE.registerConvertor(new MeterConvertor());
44 INSTANCE.registerConvertor(new MeterStatsResponseConvertor());
45 INSTANCE.registerConvertor(new MeterConfigStatsResponseConvertor());
46 INSTANCE.registerConvertor(new PortConvertor());
47 // TODO: Add MatchConvertor
48 INSTANCE.registerConvertor(new MatchResponseConvertor());
49 INSTANCE.registerConvertor(new MatchV10ResponseConvertor());
50 INSTANCE.registerConvertor(new ActionConvertor());
51 INSTANCE.registerConvertor(new ActionResponseConvertor());
52 INSTANCE.registerConvertor(new GroupConvertor());
53 INSTANCE.registerConvertor(new GroupDescStatsResponseConvertor());
54 INSTANCE.registerConvertor(new GroupStatsResponseConvertor());
55 INSTANCE.registerConvertor(new PacketOutConvertor());
56 INSTANCE.registerConvertor(new FlowConvertor());
57 INSTANCE.registerConvertor(new FlowInstructionResponseConvertor());
58 INSTANCE.registerConvertor(new FlowStatsResponseConvertor());
61 // Actual convertor keys
62 private List<Class<?>> convertorKeys = new ArrayList<>();
63 private List<Class<?>> parametrizedConvertorKeys = new ArrayList<>();
65 // Cache, that holds all registered convertors, but they can have multiple keys,
66 // based on instanceof checks in the convert method
67 private Map<Class<?>, Convertor> convertors = new ConcurrentHashMap<>();
68 private Map<Class<?>, ParametrizedConvertor> parametrizedConvertors = new ConcurrentHashMap<>();
70 private ConvertorManager() {
71 // Hiding implicit constructor
75 * Gets instance of Convertor Manager.
77 * @return the instance
79 public static ConvertorManager getInstance() {
84 public Convertor registerConvertor(final Convertor convertor) {
85 final Class<?> type = convertor.getType();
86 final Convertor result = convertors.get(type);
88 if (Objects.isNull(result)) {
89 convertorKeys.add(type);
90 convertors.put(type, convertor);
91 LOG.debug("{} is now converted by {}", type, convertor);
93 LOG.warn("Convertor for type {} is already registered", type);
100 public ParametrizedConvertor registerConvertor(final ParametrizedConvertor convertor) {
101 final Class<?> type = convertor.getType();
102 final ParametrizedConvertor result = parametrizedConvertors.get(type);
104 if (Objects.isNull(result)) {
105 parametrizedConvertorKeys.add(type);
106 parametrizedConvertors.put(type, convertor);
107 LOG.debug("{} is now converted by {}", type, convertor);
109 LOG.warn("Convertor for type {} is already registered", type);
116 @SuppressWarnings("unchecked")
117 public <FROM, TO> Optional<TO> convert(final FROM source) {
118 final Optional<Class<?>> optionalType = extractType(source);
120 if (!optionalType.isPresent()) {
121 LOG.trace("Cannot convert {}", source);
122 return Optional.empty();
125 final Class<?> type = optionalType.get();
126 Convertor convertor = convertors.get(type);
128 if (Objects.isNull(convertor)) {
129 for (final Class<?> key : convertorKeys) {
130 if (key.isAssignableFrom(type)) {
131 convertor = convertors.get(key);
132 convertors.put(type, convertor);
133 LOG.debug("{} is now converted by {}", type, convertor);
138 if (Objects.isNull(convertor)) {
139 LOG.warn("Convertor for {} not found", type);
140 return Optional.empty();
144 return Optional.of((TO) convertor.convert(source));
148 @SuppressWarnings("unchecked")
149 public <FROM, TO, DATA extends ConvertorData> Optional<TO> convert(final FROM source, final DATA data) {
150 final Optional<Class<?>> optionalType = extractType(source);
152 if (!optionalType.isPresent()) {
153 LOG.trace("Cannot convert {}", source);
154 return Optional.empty();
157 final Class<?> type = optionalType.get();
158 ParametrizedConvertor convertor = parametrizedConvertors.get(type);
160 if (Objects.isNull(convertor)) {
161 for (final Class<?> key : parametrizedConvertorKeys) {
162 if (key.isAssignableFrom(type)) {
163 convertor = parametrizedConvertors.get(key);
164 parametrizedConvertors.put(type, convertor);
165 LOG.debug("{} is now converted by {}", type, convertor);
170 if (Objects.isNull(convertor)) {
171 LOG.warn("Convertor for {} not found", type);
172 return Optional.empty();
176 return Optional.of((TO) convertor.convert(source, data));
179 private <FROM> Optional<Class<?>> extractType(FROM source) {
180 if (Objects.isNull(source)) {
181 LOG.trace("Cannot extract type from source, because it is null");
182 return Optional.empty();
185 Class<?> type = source.getClass();
187 if (source instanceof Collection) {
188 final Optional first = ((Collection) source).stream().findFirst();
190 if (!first.isPresent()) {
191 LOG.trace("Cannot extract type {}, because it is empty collection", type);
192 return Optional.empty();
195 type = first.get().getClass();
198 return Optional.of(type);