Issue fix for config subsystem
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / dependencyresolver / DependencyResolverManager.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
9
10 import static com.google.common.base.Preconditions.checkState;
11
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;
20 import java.util.Map;
21 import javax.annotation.concurrent.GuardedBy;
22 import javax.management.InstanceAlreadyExistsException;
23 import javax.management.MBeanServer;
24 import org.opendaylight.controller.config.api.DependencyResolver;
25 import org.opendaylight.controller.config.api.DependencyResolverFactory;
26 import org.opendaylight.controller.config.api.JmxAttribute;
27 import org.opendaylight.controller.config.api.ModuleIdentifier;
28 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
29 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
30 import org.opendaylight.controller.config.manager.impl.CommitInfo;
31 import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
32 import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
33 import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
34 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
35 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
36 import org.opendaylight.controller.config.spi.Module;
37 import org.opendaylight.controller.config.spi.ModuleFactory;
38 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
39 import org.osgi.framework.BundleContext;
40
41 /**
42  * Holds information about modules being created and destroyed within this
43  * transaction. Observes usage of DependencyResolver within modules to figure
44  * out dependency tree.
45  */
46 public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
47     @GuardedBy("this")
48     private final Map<ModuleIdentifier, DependencyResolverImpl> 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 CodecRegistry codecRegistry;
54     private final DeadlockMonitor deadlockMonitor;
55     private final MBeanServer mBeanServer;
56
57     public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
58                                      TransactionStatus transactionStatus,
59                                      ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry,
60                                      MBeanServer mBeanServer) {
61         this.transactionIdentifier = transactionIdentifier;
62         this.modulesHolder = new ModulesHolder(transactionIdentifier);
63         this.transactionStatus = transactionStatus;
64         this.readableRegistry = readableRegistry;
65         this.codecRegistry = codecRegistry;
66         this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
67         this.mBeanServer = mBeanServer;
68     }
69
70     @Override
71     public DependencyResolver createDependencyResolver(ModuleIdentifier moduleIdentifier) {
72         return getOrCreate(moduleIdentifier);
73     }
74
75     public synchronized DependencyResolverImpl getOrCreate(ModuleIdentifier name) {
76         DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name);
77         if (dependencyResolver == null) {
78             transactionStatus.checkNotCommitted();
79             dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry,
80                     codecRegistry, transactionIdentifier.getName(), mBeanServer);
81             moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver);
82         }
83         return dependencyResolver;
84     }
85
86     /**
87      * Get all dependency resolvers, including those that belong to destroyed
88      * things?
89      */
90     private List<DependencyResolverImpl> getAllSorted() {
91         transactionStatus.checkCommitted();
92         List<DependencyResolverImpl> sorted = new ArrayList<>(
93                 moduleIdentifiersToDependencyResolverMap.values());
94         for (DependencyResolverImpl dri : sorted) {
95             dri.countMaxDependencyDepth(this);
96         }
97         Collections.sort(sorted);
98         return sorted;
99     }
100
101     public List<ModuleIdentifier> getSortedModuleIdentifiers() {
102         List<ModuleIdentifier> result = new ArrayList<>(
103                 moduleIdentifiersToDependencyResolverMap.size());
104         for (DependencyResolverImpl dri : getAllSorted()) {
105             ModuleIdentifier driName = dri.getIdentifier();
106             result.add(driName);
107         }
108         return result;
109     }
110
111     public ModuleInternalTransactionalInfo destroyModule(
112             ModuleIdentifier moduleIdentifier) {
113         transactionStatus.checkNotCommitted();
114         ModuleInternalTransactionalInfo found = modulesHolder
115                 .destroyModule(moduleIdentifier);
116         moduleIdentifiersToDependencyResolverMap.remove(moduleIdentifier);
117         return found;
118     }
119
120     // protect write access
121
122     public void put(
123             final ModuleIdentifier moduleIdentifier,
124             final Module module,
125             ModuleFactory moduleFactory,
126             ModuleInternalInfo maybeOldInternalInfo,
127             TransactionModuleJMXRegistration transactionModuleJMXRegistration,
128             boolean isDefaultBean, BundleContext bundleContext) {
129         transactionStatus.checkNotCommitted();
130
131         Class<? extends Module> moduleClass = Module.class;
132         if (module instanceof RuntimeBeanRegistratorAwareModule) {
133             moduleClass = RuntimeBeanRegistratorAwareModule.class;
134         }
135         Module proxiedModule = Reflection.newProxy(moduleClass, new AbstractInvocationHandler() {
136             // optimization: subsequent calls to getInstance MUST return the same value during transaction,
137             // so it is safe to cache the response
138             private Object cachedInstance;
139
140             @Override
141             protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
142                 boolean isGetInstance = "getInstance".equals(method.getName());
143                 if (isGetInstance) {
144                     if (cachedInstance != null) {
145                         return cachedInstance;
146                     }
147
148                     checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
149                     deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
150                 }
151                 try {
152                     Object response = method.invoke(module, args);
153                     if (isGetInstance) {
154                         cachedInstance = response;
155                     }
156                     return response;
157                 } catch(InvocationTargetException e) {
158                     throw e.getCause();
159                 } finally {
160                     if (isGetInstance) {
161                         deadlockMonitor.setCurrentlyInstantiatedModule(null);
162                     }
163                 }
164             }
165         });
166
167
168         ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
169                 moduleIdentifier, proxiedModule, moduleFactory,
170                 maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module, bundleContext);
171         modulesHolder.put(moduleInternalTransactionalInfo);
172     }
173
174     // wrapped methods:
175
176     public CommitInfo toCommitInfo() {
177         return modulesHolder.toCommitInfo();
178     }
179
180     public Module findModule(ModuleIdentifier moduleIdentifier,
181                              JmxAttribute jmxAttributeForReporting) {
182         return modulesHolder.findModule(moduleIdentifier,
183                 jmxAttributeForReporting);
184     }
185
186     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
187         return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
188     }
189
190     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
191                                            JmxAttribute jmxAttributeForReporting) {
192         return modulesHolder.findModuleFactory(moduleIdentifier,
193                 jmxAttributeForReporting);
194     }
195
196     public Map<ModuleIdentifier, Module> getAllModules() {
197         return modulesHolder.getAllModules();
198     }
199
200     public void assertNotExists(ModuleIdentifier moduleIdentifier)
201             throws InstanceAlreadyExistsException {
202         modulesHolder.assertNotExists(moduleIdentifier);
203     }
204
205     public List<ModuleIdentifier> findAllByFactory(ModuleFactory factory) {
206         List<ModuleIdentifier> result = new ArrayList<>();
207         for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
208             if (factory.equals(info.getModuleFactory())) {
209                 result.add(info.getIdentifier());
210             }
211         }
212         return result;
213     }
214
215     public void close() {
216         deadlockMonitor.close();
217     }
218
219 }