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;
51 //TODO: check for cycles
53 public void validateDependency(
54 Class<? extends AbstractServiceInterface> expectedServiceInterface,
55 ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) {
57 transactionStatus.checkNotCommitted();
58 if (expectedServiceInterface == null) {
59 throw new NullPointerException(
60 "Parameter 'expectedServiceInterface' is null");
62 if (jmxAttribute == null)
63 throw new NullPointerException("Parameter 'jmxAttribute' is null");
65 JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON,
66 "is null, " + "expected dependency implementing "
67 + expectedServiceInterface, jmxAttribute);
69 // check that objectName belongs to this transaction - this should be
71 // in DynamicWritableWrapper
72 boolean hasTransaction = ObjectNameUtil
73 .getTransactionName(dependentModuleReadOnlyON) != null;
74 JmxAttributeValidationException.checkCondition(
75 hasTransaction == false,
76 format("ObjectName should not contain "
77 + "transaction name. %s set to %s. ", jmxAttribute,
78 dependentModuleReadOnlyON), jmxAttribute);
80 ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil
83 ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
85 boolean implementsSI = foundFactory
86 .isModuleImplementingServiceInterface(expectedServiceInterface);
87 if (implementsSI == false) {
88 String message = format(
89 "Found module factory does not expose expected service interface. "
90 + "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
92 foundFactory.getImplementationName(), foundFactory,
93 expectedServiceInterface, dependentModuleReadOnlyON,
95 throw new JmxAttributeValidationException(message, jmxAttribute);
98 dependencies.add(moduleIdentifier);
105 //TODO: check for cycles
107 public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
108 JmxAttribute jmxAttribute) {
109 if (expectedType == null || dependentON == null || jmxAttribute == null) {
110 throw new IllegalArgumentException(format(
111 "Null parameters not allowed, got {} {} {}", expectedType,
112 dependentON, jmxAttribute));
115 transactionStatus.checkCommitStarted();
116 transactionStatus.checkNotCommitted();
118 ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
119 dependentON, ObjectNameUtil.TYPE_MODULE);
120 Module module = modulesHolder.findModule(dependentModuleIdentifier,
122 synchronized (this) {
123 dependencies.add(dependentModuleIdentifier);
125 AutoCloseable instance = module.getInstance();
126 if (instance == null) {
127 String message = format(
128 "Error while %s resolving instance %s. getInstance() returned null. "
129 + "Expected type %s , attribute %s", name,
130 dependentModuleIdentifier, expectedType, jmxAttribute);
131 throw new JmxAttributeValidationException(message, jmxAttribute);
134 T result = expectedType.cast(instance);
136 } catch (ClassCastException e) {
137 String message = format(
138 "Instance cannot be cast to expected type. Instance class is %s , "
139 + "expected type %s , attribute %s",
140 instance.getClass(), expectedType, jmxAttribute);
141 throw new JmxAttributeValidationException(message, e, jmxAttribute);
146 public int compareTo(DependencyResolverImpl o) {
147 transactionStatus.checkCommitted();
148 return Integer.compare(getMaxDependencyDepth(),
149 o.getMaxDependencyDepth());
152 private Integer maxDependencyDepth;
154 int getMaxDependencyDepth() {
155 if (maxDependencyDepth == null) {
156 throw new IllegalStateException("Dependency depth was not computed");
158 return maxDependencyDepth;
161 public void countMaxDependencyDepth(DependencyResolverManager manager) {
162 transactionStatus.checkCommitted();
163 if (maxDependencyDepth == null) {
164 maxDependencyDepth = getMaxDepth(this, manager,
165 new LinkedHashSet<ModuleIdentifier>());
169 private static int getMaxDepth(DependencyResolverImpl impl,
170 DependencyResolverManager manager,
171 LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
173 LinkedHashSet<ModuleIdentifier> chainForDetectingCycles2 = new LinkedHashSet<>(
174 chainForDetectingCycles);
175 chainForDetectingCycles2.add(impl.getIdentifier());
176 for (ModuleIdentifier dependencyName : impl.dependencies) {
177 DependencyResolverImpl dependentDRI = manager
178 .getOrCreate(dependencyName);
179 if (chainForDetectingCycles2.contains(dependencyName)) {
180 throw new IllegalStateException(format(
181 "Cycle detected, {} contains {}",
182 chainForDetectingCycles2, dependencyName));
185 if (dependentDRI.maxDependencyDepth != null) {
186 subDepth = dependentDRI.maxDependencyDepth;
188 subDepth = getMaxDepth(dependentDRI, manager,
189 chainForDetectingCycles2);
190 dependentDRI.maxDependencyDepth = subDepth;
192 if (subDepth + 1 > maxDepth) {
193 maxDepth = subDepth + 1;
196 impl.maxDependencyDepth = maxDepth;
201 public ModuleIdentifier getIdentifier() {