2 * Copyright (c) 2013, 2017 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 com.google.common.base.Preconditions;
11 import com.google.common.reflect.AbstractInvocationHandler;
12 import com.google.common.reflect.Reflection;
13 import java.lang.reflect.InvocationTargetException;
14 import java.lang.reflect.Method;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.List;
20 import javax.annotation.concurrent.GuardedBy;
21 import javax.management.InstanceAlreadyExistsException;
22 import javax.management.MBeanServer;
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.manager.impl.osgi.mapping.BindingContextProvider;
36 import org.opendaylight.controller.config.spi.Module;
37 import org.opendaylight.controller.config.spi.ModuleFactory;
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>
48 moduleIdentifiersToDependencyResolverMap = new HashMap<>();
49 private final TransactionIdentifier transactionIdentifier;
50 private final ModulesHolder modulesHolder;
51 private final TransactionStatus transactionStatus;
52 private final ServiceReferenceReadableRegistry readableRegistry;
53 private final BindingContextProvider bindingContextProvider;
54 private final DeadlockMonitor deadlockMonitor;
55 private final MBeanServer beanServer;
57 public DependencyResolverManager(final TransactionIdentifier transactionIdentifier,
58 final TransactionStatus transactionStatus, final ServiceReferenceReadableRegistry readableRegistry,
59 final BindingContextProvider bindingContextProvider, final MBeanServer beanServer) {
60 this.transactionIdentifier = transactionIdentifier;
61 this.modulesHolder = new ModulesHolder(transactionIdentifier);
62 this.transactionStatus = transactionStatus;
63 this.readableRegistry = readableRegistry;
64 this.bindingContextProvider = bindingContextProvider;
65 this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
66 this.beanServer = beanServer;
70 public DependencyResolver createDependencyResolver(final ModuleIdentifier moduleIdentifier) {
71 return getOrCreate(moduleIdentifier);
74 public synchronized DependencyResolverImpl getOrCreate(final ModuleIdentifier name) {
75 DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name);
76 if (dependencyResolver == null) {
77 transactionStatus.checkNotCommitted();
78 dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry,
79 bindingContextProvider, transactionIdentifier.getName(), beanServer);
80 moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver);
82 return dependencyResolver;
86 * Get all dependency resolvers, including those that belong to destroyed
89 private List<DependencyResolverImpl> getAllSorted() {
90 transactionStatus.checkCommitStarted();
91 List<DependencyResolverImpl> sorted = new ArrayList<>(moduleIdentifiersToDependencyResolverMap.values());
92 for (DependencyResolverImpl dri : sorted) {
93 dri.countMaxDependencyDepth(this);
95 Collections.sort(sorted);
99 public List<ModuleIdentifier> getSortedModuleIdentifiers() {
100 List<ModuleIdentifier> result = new ArrayList<>(moduleIdentifiersToDependencyResolverMap.size());
101 for (DependencyResolverImpl dri : getAllSorted()) {
102 ModuleIdentifier driName = dri.getIdentifier();
108 public ModuleInternalTransactionalInfo destroyModule(final ModuleIdentifier moduleIdentifier) {
109 transactionStatus.checkNotCommitted();
110 ModuleInternalTransactionalInfo found = modulesHolder.destroyModule(moduleIdentifier);
111 moduleIdentifiersToDependencyResolverMap.remove(moduleIdentifier);
115 // protect write access
117 private static final class ModuleInvocationHandler extends AbstractInvocationHandler {
118 private final DeadlockMonitor deadlockMonitor;
119 private final ModuleIdentifier moduleIdentifier;
120 private final Module module;
122 // optimization: subsequent calls to getInstance MUST return the same value
123 // during transaction,
124 // so it is safe to cache the response
125 private Object cachedInstance;
127 ModuleInvocationHandler(final DeadlockMonitor deadlockMonitor, final ModuleIdentifier moduleIdentifier,
128 final Module module) {
129 this.deadlockMonitor = Preconditions.checkNotNull(deadlockMonitor);
130 this.moduleIdentifier = Preconditions.checkNotNull(moduleIdentifier);
131 this.module = Preconditions.checkNotNull(module);
135 protected Object handleInvocation(final Object proxy, final Method method, final Object[] args)
137 boolean isGetInstance = "getInstance".equals(method.getName());
139 if (cachedInstance != null) {
140 return cachedInstance;
143 Preconditions.checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
144 deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
147 Object response = method.invoke(module, args);
149 cachedInstance = response;
152 } catch (final InvocationTargetException e) {
156 deadlockMonitor.setCurrentlyInstantiatedModule(null);
162 public void put(final ModuleIdentifier moduleIdentifier, final Module module, final ModuleFactory moduleFactory,
163 final ModuleInternalInfo maybeOldInternalInfo,
164 final TransactionModuleJMXRegistration transactionModuleJMXRegistration, final boolean isDefaultBean,
165 final BundleContext bundleContext) {
166 transactionStatus.checkNotCommitted();
168 Class<? extends Module> moduleClass = Module.class;
169 if (module instanceof RuntimeBeanRegistratorAwareModule) {
170 moduleClass = RuntimeBeanRegistratorAwareModule.class;
172 Module proxiedModule = Reflection.newProxy(moduleClass,
173 new ModuleInvocationHandler(deadlockMonitor, moduleIdentifier, module));
174 ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
175 moduleIdentifier, proxiedModule, moduleFactory, maybeOldInternalInfo, transactionModuleJMXRegistration,
176 isDefaultBean, module, bundleContext);
177 modulesHolder.put(moduleInternalTransactionalInfo);
182 public CommitInfo toCommitInfo() {
183 return modulesHolder.toCommitInfo();
186 public Module findModule(final ModuleIdentifier moduleIdentifier, final JmxAttribute jmxAttributeForReporting) {
187 return modulesHolder.findModule(moduleIdentifier, jmxAttributeForReporting);
190 public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(
191 final ModuleIdentifier moduleIdentifier) {
192 return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
195 public ModuleFactory findModuleFactory(final ModuleIdentifier moduleIdentifier,
196 final JmxAttribute jmxAttributeForReporting) {
197 return modulesHolder.findModuleFactory(moduleIdentifier, jmxAttributeForReporting);
200 public Map<ModuleIdentifier, Module> getAllModules() {
201 return modulesHolder.getAllModules();
204 public void assertNotExists(final ModuleIdentifier moduleIdentifier) throws InstanceAlreadyExistsException {
205 modulesHolder.assertNotExists(moduleIdentifier);
208 public List<ModuleIdentifier> findAllByFactory(final ModuleFactory factory) {
209 List<ModuleIdentifier> result = new ArrayList<>();
210 for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
211 if (factory.equals(info.getModuleFactory())) {
212 result.add(info.getIdentifier());
219 public void close() {
220 modulesHolder.close();
221 deadlockMonitor.close();