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