2 * Copyright (c) 2013 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.controller.config.manager.impl;
10 import org.opendaylight.controller.config.api.LookupRegistry;
11 import org.opendaylight.controller.config.api.ModuleIdentifier;
12 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
13 import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
14 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
15 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
16 import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
17 import org.opendaylight.controller.config.spi.ModuleFactory;
18 import org.osgi.framework.BundleContext;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
22 import javax.management.InstanceNotFoundException;
23 import javax.management.ObjectName;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
29 import java.util.Map.Entry;
32 public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry {
33 private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class);
35 private final Map<String, ModuleFactory> factories;
36 private final Map<String, Set<String>> factoryNamesToQNames;
37 // validator of incoming ObjectNames - throws InstanceNotFoundException if not found either in registry or transaction
38 private final LookupRegistry lookupRegistry;
39 // helper method for getting QName of SI from namespace + local name
40 private final Map<String /* namespace */, Map<String /* local name */, ServiceInterfaceAnnotation>> namespacesToAnnotations;
41 // all Service Interface qNames for sanity checking
42 private final Set<String /* qName */> allQNames;
44 // actual reference database
45 private final Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> refNames;
48 * Static constructor for config registry. Since only transaction can write to this registry, it will
51 public static ServiceReferenceReadableRegistry createInitialSRLookupRegistry() {
52 // since this is initial state, just throw exception:
53 LookupRegistry lookupRegistry = new LookupRegistry() {
55 public Set<ObjectName> lookupConfigBeans() {
56 throw new UnsupportedOperationException();
60 public Set<ObjectName> lookupConfigBeans(String moduleName) {
61 throw new UnsupportedOperationException();
65 public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
66 throw new UnsupportedOperationException();
70 public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException {
71 throw new UnsupportedOperationException();
75 public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
76 throw new InstanceNotFoundException("Cannot find " + objectName);
80 public Set<String> getAvailableModuleFactoryQNames() {
81 throw new UnsupportedOperationException();
84 return new ServiceReferenceRegistryImpl(Collections.<String, ModuleFactory>emptyMap(), lookupRegistry,
85 Collections.<String /* qName */, Map<String /* refName */, ModuleIdentifier>>emptyMap());
89 * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data.
91 public static ServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry,
92 LookupRegistry lookupRegistry, Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
94 ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry;
95 Map<String, ModuleFactory> factories = extractFactoriesMap(currentlyRegisteredFactories);
96 return new ServiceReferenceRegistryImpl(factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
100 * Copy back state to config registry after commit.
102 public static ServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, LookupRegistry lookupRegistry) {
103 ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry;
104 // even if factories do change, nothing in the mapping can change between transactions
105 return new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
108 private static Map<String, ModuleFactory> extractFactoriesMap(Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
109 Map<String, ModuleFactory> result = new HashMap<>();
110 for (Entry<String, Entry<ModuleFactory, BundleContext>> entry : currentlyRegisteredFactories.entrySet()) {
111 result.put(entry.getKey(), entry.getValue().getKey());
116 private ServiceReferenceRegistryImpl(Map<String, ModuleFactory> factories, LookupRegistry lookupRegistry,
117 Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> refNamesToCopy) {
118 this.factories = factories;
119 this.lookupRegistry = lookupRegistry;
120 Map<String, Set<String /* QName */>> factoryNamesToQNames = new HashMap<>();
121 Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
122 Set<String /* qName */> allQNames = new HashSet<>();
123 for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
124 if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) {
125 logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
126 throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry);
128 Set<ServiceInterfaceAnnotation> siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue());
129 Set<String> qNames = new HashSet<>();
130 for (ServiceInterfaceAnnotation sia: siAnnotations) {
131 qNames.add(sia.value());
133 allAnnotations.addAll(siAnnotations);
134 allQNames.addAll(qNames);
135 factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
137 this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames);
138 this.allQNames = Collections.unmodifiableSet(allQNames);
139 // fill namespacesToAnnotations
140 Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> namespacesToAnnotations =
142 for (ServiceInterfaceAnnotation sia : allAnnotations) {
143 Map<String, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(sia.namespace());
144 if (ofNamespace == null) {
145 ofNamespace = new HashMap<>();
146 namespacesToAnnotations.put(sia.namespace(), ofNamespace);
148 if (ofNamespace.containsKey(sia.localName())) {
149 logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
150 sia.namespace(), sia.localName(), namespacesToAnnotations);
151 throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
153 ofNamespace.put(sia.localName(), sia);
155 this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations);
157 Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> deepCopy = new HashMap<>();
158 for (Entry<String, Map<String, ModuleIdentifier>> outerROEntry: refNamesToCopy.entrySet()) {
159 Map<String /* refName */, ModuleIdentifier> innerWritableMap = new HashMap<>();
160 deepCopy.put(outerROEntry.getKey(), innerWritableMap);
161 for (Entry<String, ModuleIdentifier> innerROEntry: outerROEntry.getValue().entrySet()) {
162 innerWritableMap.put(innerROEntry.getKey(), innerROEntry.getValue());
165 this.refNames = deepCopy;
166 logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
167 logger.trace("refNames:{}", refNames);
172 public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
173 lookupRegistry.checkConfigBeanExists(objectName);
175 String factoryName = ObjectNameUtil.getFactoryName(objectName);
176 Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
177 if (serviceInterfaceAnnotations == null) {
178 logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
179 factoryName, objectName, factoryNamesToQNames);
180 throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
182 return serviceInterfaceAnnotations;
186 public String getServiceInterfaceName(String namespace, String localName) {
187 Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
188 if (ofNamespace == null) {
189 logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
190 throw new IllegalArgumentException("Cannot find namespace " + namespace);
192 ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
194 logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
195 throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
205 public Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping() {
206 Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> result = new HashMap<>();
207 for (Entry<String /* qName */, Map<String, ModuleIdentifier>> outerEntry: refNames.entrySet()) {
208 String qName = outerEntry.getKey();
209 Map<String /* refName */, ObjectName> innerMap = new HashMap<>();
210 result.put(qName, innerMap);
211 for (Entry<String /* refName */, ModuleIdentifier> innerEntry: outerEntry.getValue().entrySet()) {
212 ModuleIdentifier moduleIdentifier = innerEntry.getValue();
214 on = getObjectName(moduleIdentifier);
215 innerMap.put(innerEntry.getKey(), on);
221 private ObjectName getObjectName(ModuleIdentifier moduleIdentifier) {
224 on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
225 } catch (InstanceNotFoundException e) {
226 logger.error("Cannot find instance {}", moduleIdentifier);
227 throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
233 public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
234 Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
235 if (innerMap == null) {
236 logger.error("Cannot find qname {} in {}", serviceInterfaceName, refName);
237 throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
239 ModuleIdentifier moduleIdentifier = innerMap.get(refName);
240 if (moduleIdentifier == null) {
241 logger.error("Cannot find refName {} in {}, using qname {}", refName, innerMap, serviceInterfaceName);
242 throw new IllegalArgumentException("Cannot find module based on service reference " + refName);
244 return getObjectName(moduleIdentifier);
248 public Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
249 Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
250 if (innerMap == null) {
251 logger.error("Cannot find qname {} in {}", serviceInterfaceName, refNames);
252 throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
254 Map<String /* refName */, ObjectName> result = new HashMap<>();
255 for (Entry<String/* refName */, ModuleIdentifier> entry: innerMap.entrySet()) {
256 ObjectName on = getObjectName(entry.getValue());
257 result.put(entry.getKey(), on);
265 public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
266 // make sure it is found
267 lookupRegistry.checkConfigBeanExists(objectName);
268 String factoryName = ObjectNameUtil.getFactoryName(objectName);
269 // check that service interface name exist
270 Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
271 if (serviceInterfaceQNames == null) {
272 logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
273 throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
275 // supplied serviceInterfaceName must exist in this collection
276 if (serviceInterfaceQNames.contains(serviceInterfaceName) == false) {
277 logger.error("Cannot find qname {} with factory name {}, found {}", serviceInterfaceName, factoryName, serviceInterfaceQNames);
278 throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName + " within factory " + factoryName );
280 String instanceName = ObjectNameUtil.getInstanceName(objectName);
281 ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
282 Map<String /* refName */, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
284 if (ofQName == null) {
285 ofQName = new HashMap<>();
286 refNames.put(serviceInterfaceName, ofQName);
288 ofQName.put(refName, moduleIdentifier);
292 public boolean removeServiceReference(String serviceInterfaceName, String refName) {
293 // is the qname known?
294 if (allQNames.contains(serviceInterfaceName) == false) {
295 logger.error("Cannot find qname {} in {}", serviceInterfaceName, allQNames);
296 throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName);
298 Map<String, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
299 if (ofQName == null) {
302 return ofQName.remove(refName) != null;
306 public void removeAllServiceReferences() {
311 public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
312 lookupRegistry.checkConfigBeanExists(objectName);
313 String factoryName = ObjectNameUtil.getFactoryName(objectName);
314 // check that service interface name exist
315 Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
316 if (serviceInterfaceQNames == null) {
317 logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
318 throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
320 String instanceName = ObjectNameUtil.getInstanceName(objectName);
321 ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
322 boolean found = false;
323 for(String qName: serviceInterfaceQNames){
324 Map<String, ModuleIdentifier> ofQName = refNames.get(qName);
325 if (ofQName != null) {
326 for(Iterator<Entry<String, ModuleIdentifier>> it = ofQName.entrySet ().iterator(); it.hasNext();){
327 Entry<String, ModuleIdentifier> next = it.next();
328 if (next.getValue().equals(moduleIdentifier)) {
339 public String toString() {
340 return "ServiceReferenceRegistryImpl{" +
341 "refNames=" + refNames +
342 ", factoryNamesToQNames=" + factoryNamesToQNames +