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);
79 return new ServiceReferenceRegistryImpl(Collections.<String, ModuleFactory>emptyMap(), lookupRegistry,
80 Collections.<String /* qName */, Map<String /* refName */, ModuleIdentifier>>emptyMap());
84 * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data.
86 public static ServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry,
87 LookupRegistry lookupRegistry, Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
89 ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry;
90 Map<String, ModuleFactory> factories = extractFactoriesMap(currentlyRegisteredFactories);
91 return new ServiceReferenceRegistryImpl(factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
95 * Copy back state to config registry after commit.
97 public static ServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, LookupRegistry lookupRegistry) {
98 ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry;
99 // even if factories do change, nothing in the mapping can change between transactions
100 return new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
103 private static Map<String, ModuleFactory> extractFactoriesMap(Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
104 Map<String, ModuleFactory> result = new HashMap<>();
105 for (Entry<String, Entry<ModuleFactory, BundleContext>> entry : currentlyRegisteredFactories.entrySet()) {
106 result.put(entry.getKey(), entry.getValue().getKey());
111 private ServiceReferenceRegistryImpl(Map<String, ModuleFactory> factories, LookupRegistry lookupRegistry,
112 Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> refNamesToCopy) {
113 this.factories = factories;
114 this.lookupRegistry = lookupRegistry;
115 Map<String, Set<String /* QName */>> factoryNamesToQNames = new HashMap<>();
116 Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
117 Set<String /* qName */> allQNames = new HashSet<>();
118 for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
119 if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) {
120 logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
121 throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry);
123 Set<ServiceInterfaceAnnotation> siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue());
124 Set<String> qNames = new HashSet<>();
125 for (ServiceInterfaceAnnotation sia: siAnnotations) {
126 qNames.add(sia.value());
128 allAnnotations.addAll(siAnnotations);
129 allQNames.addAll(qNames);
130 factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
132 this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames);
133 this.allQNames = Collections.unmodifiableSet(allQNames);
134 // fill namespacesToAnnotations
135 Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> namespacesToAnnotations =
137 for (ServiceInterfaceAnnotation sia : allAnnotations) {
138 Map<String, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(sia.namespace());
139 if (ofNamespace == null) {
140 ofNamespace = new HashMap<>();
141 namespacesToAnnotations.put(sia.namespace(), ofNamespace);
143 if (ofNamespace.containsKey(sia.localName())) {
144 logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
145 sia.namespace(), sia.localName(), namespacesToAnnotations);
146 throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
148 ofNamespace.put(sia.localName(), sia);
150 this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations);
152 Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> deepCopy = new HashMap<>();
153 for (Entry<String, Map<String, ModuleIdentifier>> outerROEntry: refNamesToCopy.entrySet()) {
154 Map<String /* refName */, ModuleIdentifier> innerWritableMap = new HashMap<>();
155 deepCopy.put(outerROEntry.getKey(), innerWritableMap);
156 for (Entry<String, ModuleIdentifier> innerROEntry: outerROEntry.getValue().entrySet()) {
157 innerWritableMap.put(innerROEntry.getKey(), innerROEntry.getValue());
160 this.refNames = deepCopy;
161 logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
162 logger.trace("refNames:{}", refNames);
167 public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
168 lookupRegistry.checkConfigBeanExists(objectName);
170 String factoryName = ObjectNameUtil.getFactoryName(objectName);
171 Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
172 if (serviceInterfaceAnnotations == null) {
173 logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
174 factoryName, objectName, factoryNamesToQNames);
175 throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
177 return serviceInterfaceAnnotations;
181 public String getServiceInterfaceName(String namespace, String localName) {
182 Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
183 if (ofNamespace == null) {
184 logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
185 throw new IllegalArgumentException("Cannot find namespace " + namespace);
187 ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
189 logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
190 throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
200 public Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping() {
201 Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> result = new HashMap<>();
202 for (Entry<String /* qName */, Map<String, ModuleIdentifier>> outerEntry: refNames.entrySet()) {
203 String qName = outerEntry.getKey();
204 Map<String /* refName */, ObjectName> innerMap = new HashMap<>();
205 result.put(qName, innerMap);
206 for (Entry<String /* refName */, ModuleIdentifier> innerEntry: outerEntry.getValue().entrySet()) {
207 ModuleIdentifier moduleIdentifier = innerEntry.getValue();
209 on = getObjectName(moduleIdentifier);
210 innerMap.put(innerEntry.getKey(), on);
216 private ObjectName getObjectName(ModuleIdentifier moduleIdentifier) {
219 on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
220 } catch (InstanceNotFoundException e) {
221 logger.error("Cannot find instance {}", moduleIdentifier);
222 throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
228 public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
229 Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
230 if (innerMap == null) {
231 logger.error("Cannot find qname {} in {}", serviceInterfaceName, refName);
232 throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
234 ModuleIdentifier moduleIdentifier = innerMap.get(refName);
235 if (moduleIdentifier == null) {
236 logger.error("Cannot find refName {} in {}, using qname {}", refName, innerMap, serviceInterfaceName);
237 throw new IllegalArgumentException("Cannot find module based on service reference " + refName);
239 return getObjectName(moduleIdentifier);
243 public Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
244 Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
245 if (innerMap == null) {
246 logger.error("Cannot find qname {} in {}", serviceInterfaceName, refNames);
247 throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
249 Map<String /* refName */, ObjectName> result = new HashMap<>();
250 for (Entry<String/* refName */, ModuleIdentifier> entry: innerMap.entrySet()) {
251 ObjectName on = getObjectName(entry.getValue());
252 result.put(entry.getKey(), on);
260 public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
261 // make sure it is found
262 lookupRegistry.checkConfigBeanExists(objectName);
263 String factoryName = ObjectNameUtil.getFactoryName(objectName);
264 // check that service interface name exist
265 Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
266 if (serviceInterfaceQNames == null) {
267 logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
268 throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
270 // supplied serviceInterfaceName must exist in this collection
271 if (serviceInterfaceQNames.contains(serviceInterfaceName) == false) {
272 logger.error("Cannot find qname {} with factory name {}, found {}", serviceInterfaceName, factoryName, serviceInterfaceQNames);
273 throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName + " within factory " + factoryName );
275 String instanceName = ObjectNameUtil.getInstanceName(objectName);
276 ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
277 Map<String /* refName */, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
279 if (ofQName == null) {
280 ofQName = new HashMap<>();
281 refNames.put(serviceInterfaceName, ofQName);
283 ofQName.put(refName, moduleIdentifier);
287 public boolean removeServiceReference(String serviceInterfaceName, String refName) {
288 // is the qname known?
289 if (allQNames.contains(serviceInterfaceName) == false) {
290 logger.error("Cannot find qname {} in {}", serviceInterfaceName, allQNames);
291 throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName);
293 Map<String, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
294 if (ofQName == null) {
297 return ofQName.remove(refName) != null;
301 public void removeAllServiceReferences() {
306 public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
307 lookupRegistry.checkConfigBeanExists(objectName);
308 String factoryName = ObjectNameUtil.getFactoryName(objectName);
309 // check that service interface name exist
310 Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
311 if (serviceInterfaceQNames == null) {
312 logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
313 throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
315 String instanceName = ObjectNameUtil.getInstanceName(objectName);
316 ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
317 boolean found = false;
318 for(String qName: serviceInterfaceQNames){
319 Map<String, ModuleIdentifier> ofQName = refNames.get(qName);
320 if (ofQName != null) {
321 for(Iterator<Entry<String, ModuleIdentifier>> it = ofQName.entrySet ().iterator(); it.hasNext();){
322 Entry<String, ModuleIdentifier> next = it.next();
323 if (next.getValue().equals(moduleIdentifier)) {
334 public String toString() {
335 return "ServiceReferenceRegistryImpl{" +
336 "refNames=" + refNames +
337 ", factoryNamesToQNames=" + factoryNamesToQNames +