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.base.Preconditions;
13 import com.google.common.reflect.AbstractInvocationHandler;
14 import com.google.common.reflect.Reflection;
15 import java.lang.reflect.InvocationTargetException;
16 import java.lang.reflect.Method;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
22 import javax.annotation.concurrent.GuardedBy;
23 import javax.management.InstanceAlreadyExistsException;
24 import javax.management.MBeanServer;
25 import org.opendaylight.controller.config.api.DependencyResolver;
26 import org.opendaylight.controller.config.api.DependencyResolverFactory;
27 import org.opendaylight.controller.config.api.JmxAttribute;
28 import org.opendaylight.controller.config.api.ModuleIdentifier;
29 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
30 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
31 import org.opendaylight.controller.config.manager.impl.CommitInfo;
32 import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
33 import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
34 import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
35 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
36 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
37 import org.opendaylight.controller.config.manager.impl.osgi.mapping.BindingContextProvider;
38 import org.opendaylight.controller.config.spi.Module;
39 import org.opendaylight.controller.config.spi.ModuleFactory;
40 import org.osgi.framework.BundleContext;
43 * Holds information about modules being created and destroyed within this
44 * transaction. Observes usage of DependencyResolver within modules to figure
45 * out dependency tree.
47 public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
49 private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
50 private final TransactionIdentifier transactionIdentifier;
51 private final ModulesHolder modulesHolder;
52 private final TransactionStatus transactionStatus;
53 private final ServiceReferenceReadableRegistry readableRegistry;
54 private final BindingContextProvider bindingContextProvider;
55 private final DeadlockMonitor deadlockMonitor;
56 private final MBeanServer mBeanServer;
58 public DependencyResolverManager(final TransactionIdentifier transactionIdentifier,
59 final TransactionStatus transactionStatus,
60 final ServiceReferenceReadableRegistry readableRegistry, final BindingContextProvider bindingContextProvider,
61 final MBeanServer mBeanServer) {
62 this.transactionIdentifier = transactionIdentifier;
63 this.modulesHolder = new ModulesHolder(transactionIdentifier);
64 this.transactionStatus = transactionStatus;
65 this.readableRegistry = readableRegistry;
66 this.bindingContextProvider = bindingContextProvider;
67 this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
68 this.mBeanServer = mBeanServer;
72 public DependencyResolver createDependencyResolver(final ModuleIdentifier moduleIdentifier) {
73 return getOrCreate(moduleIdentifier);
76 public synchronized DependencyResolverImpl getOrCreate(final ModuleIdentifier name) {
77 DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name);
78 if (dependencyResolver == null) {
79 transactionStatus.checkNotCommitted();
80 dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry,
81 bindingContextProvider, transactionIdentifier.getName(), mBeanServer);
82 moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver);
84 return dependencyResolver;
88 * Get all dependency resolvers, including those that belong to destroyed
91 private List<DependencyResolverImpl> getAllSorted() {
92 transactionStatus.checkCommitStarted();
93 List<DependencyResolverImpl> sorted = new ArrayList<>(
94 moduleIdentifiersToDependencyResolverMap.values());
95 for (DependencyResolverImpl dri : sorted) {
96 dri.countMaxDependencyDepth(this);
98 Collections.sort(sorted);
102 public List<ModuleIdentifier> getSortedModuleIdentifiers() {
103 List<ModuleIdentifier> result = new ArrayList<>(
104 moduleIdentifiersToDependencyResolverMap.size());
105 for (DependencyResolverImpl dri : getAllSorted()) {
106 ModuleIdentifier driName = dri.getIdentifier();
112 public ModuleInternalTransactionalInfo destroyModule(
113 final ModuleIdentifier moduleIdentifier) {
114 transactionStatus.checkNotCommitted();
115 ModuleInternalTransactionalInfo found = modulesHolder
116 .destroyModule(moduleIdentifier);
117 moduleIdentifiersToDependencyResolverMap.remove(moduleIdentifier);
121 // protect write access
123 private static final class ModuleInvocationHandler extends AbstractInvocationHandler {
124 private final DeadlockMonitor deadlockMonitor;
125 private final ModuleIdentifier moduleIdentifier;
126 private final Module module;
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;
132 ModuleInvocationHandler(final DeadlockMonitor deadlockMonitor, final ModuleIdentifier moduleIdentifier, final Module module) {
133 this.deadlockMonitor = Preconditions.checkNotNull(deadlockMonitor);
134 this.moduleIdentifier = Preconditions.checkNotNull(moduleIdentifier);
135 this.module = Preconditions.checkNotNull(module);
139 protected Object handleInvocation(final Object proxy, final Method method, final Object[] args) throws Throwable {
140 boolean isGetInstance = "getInstance".equals(method.getName());
142 if (cachedInstance != null) {
143 return cachedInstance;
146 checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
147 deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
150 Object response = method.invoke(module, args);
152 cachedInstance = response;
155 } catch(InvocationTargetException e) {
159 deadlockMonitor.setCurrentlyInstantiatedModule(null);
166 final ModuleIdentifier moduleIdentifier,
168 final ModuleFactory moduleFactory,
169 final ModuleInternalInfo maybeOldInternalInfo,
170 final TransactionModuleJMXRegistration transactionModuleJMXRegistration,
171 final boolean isDefaultBean, final BundleContext bundleContext) {
172 transactionStatus.checkNotCommitted();
174 Class<? extends Module> moduleClass = Module.class;
175 if (module instanceof RuntimeBeanRegistratorAwareModule) {
176 moduleClass = RuntimeBeanRegistratorAwareModule.class;
178 Module proxiedModule = Reflection.newProxy(moduleClass, new ModuleInvocationHandler(deadlockMonitor, moduleIdentifier, module));
179 ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
180 moduleIdentifier, proxiedModule, moduleFactory,
181 maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module, bundleContext);
182 modulesHolder.put(moduleInternalTransactionalInfo);
187 public CommitInfo toCommitInfo() {
188 return modulesHolder.toCommitInfo();
191 public Module findModule(final ModuleIdentifier moduleIdentifier,
192 final JmxAttribute jmxAttributeForReporting) {
193 return modulesHolder.findModule(moduleIdentifier,
194 jmxAttributeForReporting);
197 public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(final ModuleIdentifier moduleIdentifier) {
198 return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
201 public ModuleFactory findModuleFactory(final ModuleIdentifier moduleIdentifier,
202 final JmxAttribute jmxAttributeForReporting) {
203 return modulesHolder.findModuleFactory(moduleIdentifier,
204 jmxAttributeForReporting);
207 public Map<ModuleIdentifier, Module> getAllModules() {
208 return modulesHolder.getAllModules();
211 public void assertNotExists(final ModuleIdentifier moduleIdentifier)
212 throws InstanceAlreadyExistsException {
213 modulesHolder.assertNotExists(moduleIdentifier);
216 public List<ModuleIdentifier> findAllByFactory(final ModuleFactory factory) {
217 List<ModuleIdentifier> result = new ArrayList<>();
218 for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
219 if (factory.equals(info.getModuleFactory())) {
220 result.add(info.getIdentifier());
227 public void close() {
228 deadlockMonitor.close();