Resolve Bug:853 - remove groovy from config code generator.
[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 com.google.common.reflect.AbstractInvocationHandler;
11 import com.google.common.reflect.Reflection;
12 import org.opendaylight.controller.config.api.DependencyResolver;
13 import org.opendaylight.controller.config.api.DependencyResolverFactory;
14 import org.opendaylight.controller.config.api.JmxAttribute;
15 import org.opendaylight.controller.config.api.ModuleIdentifier;
16 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
17 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
18 import org.opendaylight.controller.config.manager.impl.CommitInfo;
19 import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
20 import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
21 import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
22 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
23 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
24 import org.opendaylight.controller.config.spi.Module;
25 import org.opendaylight.controller.config.spi.ModuleFactory;
26 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
27
28 import javax.annotation.concurrent.GuardedBy;
29 import javax.management.InstanceAlreadyExistsException;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37
38 import static com.google.common.base.Preconditions.checkState;
39
40 /**
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.
44  */
45 public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
46     @GuardedBy("this")
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;
53
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);
61     }
62
63     @Override
64     public DependencyResolver createDependencyResolver(ModuleIdentifier moduleIdentifier) {
65         return getOrCreate(moduleIdentifier);
66     }
67
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);
74         }
75         return dependencyResolver;
76     }
77
78     /**
79      * Get all dependency resolvers, including those that belong to destroyed
80      * things?
81      */
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);
88         }
89         Collections.sort(sorted);
90         return sorted;
91     }
92
93     public List<ModuleIdentifier> getSortedModuleIdentifiers() {
94         List<ModuleIdentifier> result = new ArrayList<>(
95                 moduleIdentifiersToDependencyResolverMap.size());
96         for (DependencyResolverImpl dri : getAllSorted()) {
97             ModuleIdentifier driName = dri.getIdentifier();
98             result.add(driName);
99         }
100         return result;
101     }
102
103     public ModuleInternalTransactionalInfo destroyModule(
104             ModuleIdentifier moduleIdentifier) {
105         transactionStatus.checkNotCommitted();
106         ModuleInternalTransactionalInfo found = modulesHolder
107                 .destroyModule(moduleIdentifier);
108         moduleIdentifiersToDependencyResolverMap.remove(moduleIdentifier);
109         return found;
110     }
111
112     // protect write access
113
114     public void put(
115             final ModuleIdentifier moduleIdentifier,
116             final Module module,
117             ModuleFactory moduleFactory,
118             ModuleInternalInfo maybeOldInternalInfo,
119             TransactionModuleJMXRegistration transactionModuleJMXRegistration,
120             boolean isDefaultBean) {
121         transactionStatus.checkNotCommitted();
122
123         Class<? extends Module> moduleClass = Module.class;
124         if (module instanceof RuntimeBeanRegistratorAwareModule) {
125             moduleClass = RuntimeBeanRegistratorAwareModule.class;
126         }
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;
131
132             @Override
133             protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
134                 boolean isGetInstance = method.getName().equals("getInstance");
135                 if (isGetInstance) {
136                     if (cachedInstance != null) {
137                         return cachedInstance;
138                     }
139
140                     checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
141                     deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
142                 }
143                 try {
144                     Object response = method.invoke(module, args);
145                     if (isGetInstance) {
146                         cachedInstance = response;
147                     }
148                     return response;
149                 } catch(InvocationTargetException e) {
150                     throw e.getCause();
151                 } finally {
152                     if (isGetInstance) {
153                         deadlockMonitor.setCurrentlyInstantiatedModule(null);
154                     }
155                 }
156             }
157         });
158
159
160         ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
161                 moduleIdentifier, proxiedModule, moduleFactory,
162                 maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module);
163         modulesHolder.put(moduleInternalTransactionalInfo);
164     }
165
166     // wrapped methods:
167
168     public CommitInfo toCommitInfo() {
169         return modulesHolder.toCommitInfo();
170     }
171
172     public Module findModule(ModuleIdentifier moduleIdentifier,
173                              JmxAttribute jmxAttributeForReporting) {
174         return modulesHolder.findModule(moduleIdentifier,
175                 jmxAttributeForReporting);
176     }
177
178     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
179         return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
180     }
181
182     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
183                                            JmxAttribute jmxAttributeForReporting) {
184         return modulesHolder.findModuleFactory(moduleIdentifier,
185                 jmxAttributeForReporting);
186     }
187
188     public Map<ModuleIdentifier, Module> getAllModules() {
189         return modulesHolder.getAllModules();
190     }
191
192     public void assertNotExists(ModuleIdentifier moduleIdentifier)
193             throws InstanceAlreadyExistsException {
194         modulesHolder.assertNotExists(moduleIdentifier);
195     }
196
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());
202             }
203         }
204         return result;
205     }
206
207     public void close() {
208         deadlockMonitor.close();
209     }
210
211 }