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.dependencyresolver;
10 import static com.google.common.base.Preconditions.checkState;
12 import com.google.common.reflect.AbstractInvocationHandler;
13 import com.google.common.reflect.Reflection;
14 import java.lang.reflect.InvocationTargetException;
15 import java.lang.reflect.Method;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.List;
21 import javax.annotation.concurrent.GuardedBy;
22 import javax.management.InstanceAlreadyExistsException;
23 import org.opendaylight.controller.config.api.DependencyResolver;
24 import org.opendaylight.controller.config.api.DependencyResolverFactory;
25 import org.opendaylight.controller.config.api.JmxAttribute;
26 import org.opendaylight.controller.config.api.ModuleIdentifier;
27 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
28 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
29 import org.opendaylight.controller.config.manager.impl.CommitInfo;
30 import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
31 import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
32 import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
33 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
34 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
35 import org.opendaylight.controller.config.spi.Module;
36 import org.opendaylight.controller.config.spi.ModuleFactory;
37 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
38 import org.osgi.framework.BundleContext;
41 * Holds information about modules being created and destroyed within this
42 * transaction. Observes usage of DependencyResolver within modules to figure
43 * out dependency tree.
45 public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
47 private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
48 private final ModulesHolder modulesHolder;
49 private final TransactionStatus transactionStatus;
50 private final ServiceReferenceReadableRegistry readableRegistry;
51 private final CodecRegistry codecRegistry;
52 private final DeadlockMonitor deadlockMonitor;
54 public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
55 TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
56 this.modulesHolder = new ModulesHolder(transactionIdentifier);
57 this.transactionStatus = transactionStatus;
58 this.readableRegistry = readableRegistry;
59 this.codecRegistry = codecRegistry;
60 this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
64 public DependencyResolver createDependencyResolver(ModuleIdentifier moduleIdentifier) {
65 return getOrCreate(moduleIdentifier);
68 public synchronized DependencyResolverImpl getOrCreate(ModuleIdentifier name) {
69 DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name);
70 if (dependencyResolver == null) {
71 transactionStatus.checkNotCommitted();
72 dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry, codecRegistry);
73 moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver);
75 return dependencyResolver;
79 * Get all dependency resolvers, including those that belong to destroyed
82 private List<DependencyResolverImpl> getAllSorted() {
83 transactionStatus.checkCommitted();
84 List<DependencyResolverImpl> sorted = new ArrayList<>(
85 moduleIdentifiersToDependencyResolverMap.values());
86 for (DependencyResolverImpl dri : sorted) {
87 dri.countMaxDependencyDepth(this);
89 Collections.sort(sorted);
93 public List<ModuleIdentifier> getSortedModuleIdentifiers() {
94 List<ModuleIdentifier> result = new ArrayList<>(
95 moduleIdentifiersToDependencyResolverMap.size());
96 for (DependencyResolverImpl dri : getAllSorted()) {
97 ModuleIdentifier driName = dri.getIdentifier();
103 public ModuleInternalTransactionalInfo destroyModule(
104 ModuleIdentifier moduleIdentifier) {
105 transactionStatus.checkNotCommitted();
106 ModuleInternalTransactionalInfo found = modulesHolder
107 .destroyModule(moduleIdentifier);
108 moduleIdentifiersToDependencyResolverMap.remove(moduleIdentifier);
112 // protect write access
115 final ModuleIdentifier moduleIdentifier,
117 ModuleFactory moduleFactory,
118 ModuleInternalInfo maybeOldInternalInfo,
119 TransactionModuleJMXRegistration transactionModuleJMXRegistration,
120 boolean isDefaultBean, BundleContext bundleContext) {
121 transactionStatus.checkNotCommitted();
123 Class<? extends Module> moduleClass = Module.class;
124 if (module instanceof RuntimeBeanRegistratorAwareModule) {
125 moduleClass = RuntimeBeanRegistratorAwareModule.class;
127 Module proxiedModule = Reflection.newProxy(moduleClass, new AbstractInvocationHandler() {
128 // optimization: subsequent calls to getInstance MUST return the same value during transaction,
129 // so it is safe to cache the response
130 private Object cachedInstance;
133 protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
134 boolean isGetInstance = method.getName().equals("getInstance");
136 if (cachedInstance != null) {
137 return cachedInstance;
140 checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
141 deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
144 Object response = method.invoke(module, args);
146 cachedInstance = response;
149 } catch(InvocationTargetException e) {
153 deadlockMonitor.setCurrentlyInstantiatedModule(null);
160 ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
161 moduleIdentifier, proxiedModule, moduleFactory,
162 maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module, bundleContext);
163 modulesHolder.put(moduleInternalTransactionalInfo);
168 public CommitInfo toCommitInfo() {
169 return modulesHolder.toCommitInfo();
172 public Module findModule(ModuleIdentifier moduleIdentifier,
173 JmxAttribute jmxAttributeForReporting) {
174 return modulesHolder.findModule(moduleIdentifier,
175 jmxAttributeForReporting);
178 public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
179 return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
182 public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
183 JmxAttribute jmxAttributeForReporting) {
184 return modulesHolder.findModuleFactory(moduleIdentifier,
185 jmxAttributeForReporting);
188 public Map<ModuleIdentifier, Module> getAllModules() {
189 return modulesHolder.getAllModules();
192 public void assertNotExists(ModuleIdentifier moduleIdentifier)
193 throws InstanceAlreadyExistsException {
194 modulesHolder.assertNotExists(moduleIdentifier);
197 public List<ModuleIdentifier> findAllByFactory(ModuleFactory factory) {
198 List<ModuleIdentifier> result = new ArrayList<>();
199 for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
200 if (factory.equals(info.getModuleFactory())) {
201 result.add(info.getIdentifier());
207 public void close() {
208 deadlockMonitor.close();