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 org.opendaylight.controller.config.api.DependencyResolver;
11 import org.opendaylight.controller.config.api.JmxAttribute;
12 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
13 import org.opendaylight.controller.config.api.ModuleIdentifier;
14 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
15 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
16 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
17 import org.opendaylight.controller.config.spi.Module;
18 import org.opendaylight.controller.config.spi.ModuleFactory;
20 import javax.annotation.concurrent.GuardedBy;
21 import javax.management.ObjectName;
22 import java.util.HashSet;
23 import java.util.LinkedHashSet;
26 import static java.lang.String.format;
29 * Protect {@link org.opendaylight.controller.config.spi.Module#getInstance()}
30 * by creating proxy that would throw exception if those methods are called
31 * during validation. Tracks dependencies for ordering purposes.
33 final class DependencyResolverImpl implements DependencyResolver,
34 Comparable<DependencyResolverImpl> {
35 private final ModulesHolder modulesHolder;
36 private final ModuleIdentifier name;
37 private final TransactionStatus transactionStatus;
39 private final Set<ModuleIdentifier> dependencies = new HashSet<>();
41 DependencyResolverImpl(ModuleIdentifier currentModule,
42 TransactionStatus transactionStatus, ModulesHolder modulesHolder) {
43 this.name = currentModule;
44 this.transactionStatus = transactionStatus;
45 this.modulesHolder = modulesHolder;
52 public void validateDependency(
53 Class<? extends AbstractServiceInterface> expectedServiceInterface,
54 ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) {
56 transactionStatus.checkNotCommitted();
57 if (expectedServiceInterface == null) {
58 throw new NullPointerException(
59 "Parameter 'expectedServiceInterface' is null");
61 if (jmxAttribute == null)
62 throw new NullPointerException("Parameter 'jmxAttribute' is null");
64 JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON,
65 "is null, " + "expected dependency implementing "
66 + expectedServiceInterface, jmxAttribute);
68 // check that objectName belongs to this transaction - this should be
70 // in DynamicWritableWrapper
71 boolean hasTransaction = ObjectNameUtil
72 .getTransactionName(dependentModuleReadOnlyON) != null;
73 JmxAttributeValidationException.checkCondition(
74 hasTransaction == false,
75 format("ObjectName should not contain "
76 + "transaction name. %s set to %s. ", jmxAttribute,
77 dependentModuleReadOnlyON), jmxAttribute);
79 ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil
82 ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
84 boolean implementsSI = foundFactory
85 .isModuleImplementingServiceInterface(expectedServiceInterface);
86 if (implementsSI == false) {
87 String message = format(
88 "Found module factory does not expose expected service interface. "
89 + "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
91 foundFactory.getImplementationName(), foundFactory,
92 expectedServiceInterface, dependentModuleReadOnlyON,
94 throw new JmxAttributeValidationException(message, jmxAttribute);
97 dependencies.add(moduleIdentifier);
105 public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
106 JmxAttribute jmxAttribute) {
107 if (expectedType == null || dependentON == null || jmxAttribute == null) {
108 throw new IllegalArgumentException(format(
109 "Null parameters not allowed, got {} {} {}", expectedType,
110 dependentON, jmxAttribute));
113 transactionStatus.checkCommitStarted();
114 transactionStatus.checkNotCommitted();
116 ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
117 dependentON, ObjectNameUtil.TYPE_MODULE);
118 Module module = modulesHolder.findModule(dependentModuleIdentifier,
120 synchronized (this) {
121 dependencies.add(dependentModuleIdentifier);
123 AutoCloseable instance = module.getInstance();
124 if (instance == null) {
125 String message = format(
126 "Error while %s resolving instance %s. getInstance() returned null. "
127 + "Expected type %s , attribute %s", name,
128 dependentModuleIdentifier, expectedType, jmxAttribute);
129 throw new JmxAttributeValidationException(message, jmxAttribute);
132 T result = expectedType.cast(instance);
134 } catch (ClassCastException e) {
135 String message = format(
136 "Instance cannot be cast to expected type. Instance class is %s , "
137 + "expected type %s , attribute %s",
138 instance.getClass(), expectedType, jmxAttribute);
139 throw new JmxAttributeValidationException(message, e, jmxAttribute);
144 public int compareTo(DependencyResolverImpl o) {
145 transactionStatus.checkCommitted();
146 return Integer.compare(getMaxDependencyDepth(),
147 o.getMaxDependencyDepth());
150 private Integer maxDependencyDepth;
152 int getMaxDependencyDepth() {
153 if (maxDependencyDepth == null) {
154 throw new IllegalStateException("Dependency depth was not computed");
156 return maxDependencyDepth;
159 public void countMaxDependencyDepth(DependencyResolverManager manager) {
160 transactionStatus.checkCommitted();
161 if (maxDependencyDepth == null) {
162 maxDependencyDepth = getMaxDepth(this, manager,
163 new LinkedHashSet<ModuleIdentifier>());
167 private static int getMaxDepth(DependencyResolverImpl impl,
168 DependencyResolverManager manager,
169 LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
171 LinkedHashSet<ModuleIdentifier> chainForDetectingCycles2 = new LinkedHashSet<>(
172 chainForDetectingCycles);
173 chainForDetectingCycles2.add(impl.getIdentifier());
174 for (ModuleIdentifier dependencyName : impl.dependencies) {
175 DependencyResolverImpl dependentDRI = manager
176 .getOrCreate(dependencyName);
177 if (chainForDetectingCycles2.contains(dependencyName)) {
178 throw new IllegalStateException(format(
179 "Cycle detected, {} contains {}",
180 chainForDetectingCycles2, dependencyName));
183 if (dependentDRI.maxDependencyDepth != null) {
184 subDepth = dependentDRI.maxDependencyDepth;
186 subDepth = getMaxDepth(dependentDRI, manager,
187 chainForDetectingCycles2);
188 dependentDRI.maxDependencyDepth = subDepth;
190 if (subDepth + 1 > maxDepth) {
191 maxDepth = subDepth + 1;
194 impl.maxDependencyDepth = maxDepth;
199 public ModuleIdentifier getIdentifier() {