Bug 5540 - MeterStatsResponseConvertor, MeterConfigStatsResponseConvertor
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / ConvertorManager.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Objects;
18 import java.util.Optional;
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.openflowplugin.openflow.md.core.sal.convertor.common.ParametrizedConvertor;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Manages various convertors and allows to use them all in one generic way
27  */
28 public class ConvertorManager {
29     private static final Logger LOG = LoggerFactory.getLogger(ConvertorManager.class);
30     private static ConvertorManager INSTANCE;
31
32     static {
33         INSTANCE = new ConvertorManager();
34         // All convertors are registered here
35         INSTANCE.registerConvertor(new TableFeaturesConvertor());
36         INSTANCE.registerConvertor(new TableFeaturesResponseConvertor());
37         INSTANCE.registerConvertor(new MeterConvertor());
38         INSTANCE.registerConvertor(new MeterStatsResponseConvertor());
39         INSTANCE.registerConvertor(new MeterConfigStatsResponseConvertor());
40     }
41
42     // Actual convertor keys
43     private List<Class<?>> convertorKeys = new ArrayList<>();
44     private List<Class<?>> parametrizedConvertorKeys = new ArrayList<>();
45
46     // Cache, that holds all registered convertors, but they can have multiple keys,
47     // based on instanceof checks in the convert method
48     private Map<Class<?>, Convertor> convertors = new HashMap<>();
49     private Map<Class<?>, ParametrizedConvertor> parametrizedConvertors = new HashMap<>();
50
51     private ConvertorManager() {
52         // Hiding implicit constructor
53     }
54
55     /**
56      * Gets instance of Convertor Manager.
57      *
58      * @return the instance
59      */
60     public static ConvertorManager getInstance() {
61         return INSTANCE;
62     }
63
64     /**
65      * Register convertor.
66      *
67      * @param convertor the convertor
68      * @return if registration was successful
69      */
70     public boolean registerConvertor(final Convertor convertor) {
71         final Class<?> type = convertor.getType();
72
73         if (convertors.containsKey(type)) {
74             LOG.warn("Convertor for type {} is already registered", type);
75             return false;
76         }
77
78         convertorKeys.add(type);
79         convertors.put(type, convertor);
80         LOG.debug("{} is now converted by {}", type, convertor);
81         return true;
82     }
83
84     /**
85      * Register convertor.
86      *
87      * @param convertor the convertor
88      * @return if registration was successful
89      */
90     public boolean registerConvertor(final ParametrizedConvertor convertor) {
91         final Class<?> type = convertor.getType();
92
93         if (parametrizedConvertors.containsKey(type)) {
94             LOG.warn("Convertor for type {} is already registered", type);
95             return false;
96         }
97
98         parametrizedConvertorKeys.add(type);
99         parametrizedConvertors.put(type, convertor);
100         LOG.debug("{} is now converted by {}", type, convertor);
101         return true;
102     }
103
104     /**
105      * Lookup and use convertor by specified type, then converts source and returns converted result
106      *
107      * @param <FROM> the source type
108      * @param <TO>   the result type
109      * @param source the source
110      * @return the result (can be empty, if no convertor was found)
111      */
112     @SuppressWarnings("unchecked")
113     public <FROM, TO> Optional<TO> convert(final FROM source) {
114         if (Objects.isNull(source)) {
115             LOG.trace("Cannot convert source, because it is null");
116             return Optional.empty();
117         }
118
119         Class<?> type = source.getClass();
120
121         if (source instanceof Collection) {
122             final Iterator it = ((Collection) source).iterator();
123             Object next = null;
124
125             if (it.hasNext()) {
126                 next = it.next();
127             }
128
129             if (Objects.isNull(next)) {
130                 LOG.trace("Cannot convert {}, because it is empty collection", type);
131                 return Optional.empty();
132             }
133
134             type = next.getClass();
135         }
136
137         Convertor convertor = null;
138
139         if (!convertors.containsKey(type)) {
140             boolean found = false;
141
142             for (Class<?> key : convertorKeys) {
143                 if (key.isAssignableFrom(type)) {
144                     convertor = convertors.get(key);
145                     convertors.put(type, convertor);
146                     LOG.debug("{} is now converted by {}", type, convertor);
147                     found = true;
148                     break;
149                 }
150             }
151
152             if (!found) {
153                 LOG.error("Convertor for {} not found", type);
154                 return Optional.empty();
155             }
156         }
157
158         if (Objects.isNull(convertor)) {
159             convertor = convertors.get(type);
160         }
161
162         final Object result = convertor.convert(source);
163         return Optional.of((TO) result);
164     }
165
166     /**
167      * Lookup and use convertor by specified type, then converts source and returns converted result
168      *
169      * @param <FROM> the source type
170      * @param <TO>   the result type
171      * @param <DATA> the data type
172      * @param source the source
173      * @param data   convertor data
174      * @return the result (can be empty, if no convertor was found)
175      */
176     @SuppressWarnings("unchecked")
177     public <FROM, TO, DATA extends ConvertorData> Optional<TO> convert(final FROM source, final DATA data) {
178         if (Objects.isNull(source)) {
179             LOG.trace("Cannot convert source, because it is null");
180             return Optional.empty();
181         }
182
183         Class<?> type = source.getClass();
184
185         if (source instanceof Collection) {
186             final Iterator it = ((Collection) source).iterator();
187             Object next = null;
188
189             if (it.hasNext()) {
190                 next = it.next();
191             }
192
193             if (Objects.isNull(next)) {
194                 LOG.trace("Cannot convert {}, because it is empty collection", type);
195                 return Optional.empty();
196             }
197
198             type = next.getClass();
199         }
200
201         ParametrizedConvertor convertor = null;
202
203         if (!parametrizedConvertors.containsKey(type)) {
204             boolean found = false;
205
206             for (Class<?> key : parametrizedConvertorKeys) {
207                 if (key.isAssignableFrom(type)) {
208                     convertor = parametrizedConvertors.get(key);
209                     parametrizedConvertors.put(type, convertor);
210                     LOG.debug("{} is now converted by {}", type, convertor);
211                     found = true;
212                     break;
213                 }
214             }
215
216             if (!found) {
217                 LOG.error("Convertor for {} not found", type);
218                 return Optional.empty();
219             }
220         }
221
222         if (Objects.isNull(convertor)) {
223             convertor = parametrizedConvertors.get(type);
224         }
225
226         final Object result = convertor.convert(source, data);
227         return Optional.of((TO) result);
228     }
229 }