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 java.lang.String.format;
12 import java.util.HashSet;
13 import java.util.LinkedHashSet;
16 import javax.annotation.concurrent.GuardedBy;
17 import javax.management.ObjectName;
19 import org.opendaylight.controller.config.api.DependencyResolver;
20 import org.opendaylight.controller.config.api.JmxAttribute;
21 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
22 import org.opendaylight.controller.config.api.ModuleIdentifier;
23 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
24 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
25 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
26 import org.opendaylight.controller.config.spi.Module;
27 import org.opendaylight.controller.config.spi.ModuleFactory;
30 * Protect {@link org.opendaylight.controller.config.spi.Module#getInstance()}
31 * by creating proxy that would throw exception if those methods are called
32 * during validation. Tracks dependencies for ordering purposes.
34 final class DependencyResolverImpl implements DependencyResolver,
35 Comparable<DependencyResolverImpl> {
36 private final ModulesHolder modulesHolder;
37 private final ModuleIdentifier name;
38 private final TransactionStatus transactionStatus;
40 private final Set<ModuleIdentifier> dependencies = new HashSet<>();
42 DependencyResolverImpl(ModuleIdentifier currentModule,
43 TransactionStatus transactionStatus, ModulesHolder modulesHolder) {
44 this.name = currentModule;
45 this.transactionStatus = transactionStatus;
46 this.modulesHolder = modulesHolder;
49 public ModuleIdentifier getName() {
57 public void validateDependency(
58 Class<? extends AbstractServiceInterface> expectedServiceInterface,
59 ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) {
61 transactionStatus.checkNotCommitted();
62 if (expectedServiceInterface == null) {
63 throw new NullPointerException(
64 "Parameter 'expectedServiceInterface' is null");
66 if (jmxAttribute == null)
67 throw new NullPointerException("Parameter 'jmxAttribute' is null");
69 JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON,
70 "is null, " + "expected dependency implementing "
71 + expectedServiceInterface, jmxAttribute);
73 // check that objectName belongs to this transaction - this should be
75 // in DynamicWritableWrapper
76 boolean hasTransaction = ObjectNameUtil
77 .getTransactionName(dependentModuleReadOnlyON) != null;
78 JmxAttributeValidationException.checkCondition(
79 hasTransaction == false,
80 format("ObjectName should not contain "
81 + "transaction name. %s set to %s. ", jmxAttribute,
82 dependentModuleReadOnlyON), jmxAttribute);
84 ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil
87 ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
89 boolean implementsSI = foundFactory
90 .isModuleImplementingServiceInterface(expectedServiceInterface);
91 if (implementsSI == false) {
92 String message = format(
93 "Found module factory does not expose expected service interface. "
94 + "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
96 foundFactory.getImplementationName(), foundFactory,
97 expectedServiceInterface, dependentModuleReadOnlyON,
99 throw new JmxAttributeValidationException(message, jmxAttribute);
101 synchronized (this) {
102 dependencies.add(moduleIdentifier);
110 public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
111 JmxAttribute jmxAttribute) {
112 if (expectedType == null || dependentON == null || jmxAttribute == null) {
113 throw new IllegalArgumentException(format(
114 "Null parameters not allowed, got {} {} {}", expectedType,
115 dependentON, jmxAttribute));
118 transactionStatus.checkCommitStarted();
119 transactionStatus.checkNotCommitted();
121 ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
122 dependentON, ObjectNameUtil.TYPE_MODULE);
123 Module module = modulesHolder.findModule(dependentModuleIdentifier,
125 synchronized (this) {
126 dependencies.add(dependentModuleIdentifier);
128 AutoCloseable instance = module.getInstance();
129 if (instance == null) {
130 String message = format(
131 "Error while %s resolving instance %s. getInstance() returned null. "
132 + "Expected type %s , attribute %s", name,
133 dependentModuleIdentifier, expectedType, jmxAttribute);
134 throw new JmxAttributeValidationException(message, jmxAttribute);
137 T result = expectedType.cast(instance);
139 } catch (ClassCastException e) {
140 String message = format(
141 "Instance cannot be cast to expected type. Instance class is %s , "
142 + "expected type %s , attribute %s",
143 instance.getClass(), expectedType, jmxAttribute);
144 throw new JmxAttributeValidationException(message, e, jmxAttribute);
149 public int compareTo(DependencyResolverImpl o) {
150 transactionStatus.checkCommitted();
151 return Integer.compare(getMaxDependencyDepth(),
152 o.getMaxDependencyDepth());
155 private Integer maxDependencyDepth;
157 int getMaxDependencyDepth() {
158 if (maxDependencyDepth == null) {
159 throw new IllegalStateException("Dependency depth was not computed");
161 return maxDependencyDepth;
164 public void countMaxDependencyDepth(DependencyResolverManager manager) {
165 transactionStatus.checkCommitted();
166 if (maxDependencyDepth == null) {
167 maxDependencyDepth = getMaxDepth(this, manager,
168 new LinkedHashSet<ModuleIdentifier>());
172 private static int getMaxDepth(DependencyResolverImpl impl,
173 DependencyResolverManager manager,
174 LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
176 LinkedHashSet<ModuleIdentifier> chainForDetectingCycles2 = new LinkedHashSet<>(
177 chainForDetectingCycles);
178 chainForDetectingCycles2.add(impl.getName());
179 for (ModuleIdentifier dependencyName : impl.dependencies) {
180 DependencyResolverImpl dependentDRI = manager
181 .getOrCreate(dependencyName);
182 if (chainForDetectingCycles2.contains(dependencyName)) {
183 throw new IllegalStateException(format(
184 "Cycle detected, {} contains {}",
185 chainForDetectingCycles2, dependencyName));
188 if (dependentDRI.maxDependencyDepth != null) {
189 subDepth = dependentDRI.maxDependencyDepth;
191 subDepth = getMaxDepth(dependentDRI, manager,
192 chainForDetectingCycles2);
193 dependentDRI.maxDependencyDepth = subDepth;
195 if (subDepth + 1 > maxDepth) {
196 maxDepth = subDepth + 1;
199 impl.maxDependencyDepth = maxDepth;