creating a default subnet
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / dependencyresolver / DependencyResolverImpl.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 java.lang.String.format;
11
12 import java.util.HashSet;
13 import java.util.LinkedHashSet;
14 import java.util.Set;
15
16 import javax.annotation.concurrent.GuardedBy;
17 import javax.management.ObjectName;
18
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;
28 import org.opendaylight.yangtools.concepts.Identifiable;
29
30 /**
31  * Protect {@link org.opendaylight.controller.config.spi.Module#getInstance()}
32  * by creating proxy that would throw exception if those methods are called
33  * during validation. Tracks dependencies for ordering purposes.
34  */
35 final class DependencyResolverImpl implements DependencyResolver,
36        Identifiable<ModuleIdentifier>, Comparable<DependencyResolverImpl> {
37     private final ModulesHolder modulesHolder;
38     private final ModuleIdentifier name;
39     private final TransactionStatus transactionStatus;
40     @GuardedBy("this")
41     private final Set<ModuleIdentifier> dependencies = new HashSet<>();
42
43     DependencyResolverImpl(ModuleIdentifier currentModule,
44             TransactionStatus transactionStatus, ModulesHolder modulesHolder) {
45         this.name = currentModule;
46         this.transactionStatus = transactionStatus;
47         this.modulesHolder = modulesHolder;
48     }
49
50     @Deprecated
51     public ModuleIdentifier getName() {
52         return name;
53     }
54
55     /**
56      * {@inheritDoc}
57      */
58     @Override
59     public void validateDependency(
60             Class<? extends AbstractServiceInterface> expectedServiceInterface,
61             ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) {
62
63         transactionStatus.checkNotCommitted();
64         if (expectedServiceInterface == null) {
65             throw new NullPointerException(
66                     "Parameter 'expectedServiceInterface' is null");
67         }
68         if (jmxAttribute == null)
69             throw new NullPointerException("Parameter 'jmxAttribute' is null");
70
71         JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON,
72                 "is null, " + "expected dependency implementing "
73                         + expectedServiceInterface, jmxAttribute);
74
75         // check that objectName belongs to this transaction - this should be
76         // stripped
77         // in DynamicWritableWrapper
78         boolean hasTransaction = ObjectNameUtil
79                 .getTransactionName(dependentModuleReadOnlyON) != null;
80         JmxAttributeValidationException.checkCondition(
81                 hasTransaction == false,
82                 format("ObjectName should not contain "
83                         + "transaction name. %s set to %s. ", jmxAttribute,
84                         dependentModuleReadOnlyON), jmxAttribute);
85
86         ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil
87                 .TYPE_MODULE);
88
89         ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
90
91         boolean implementsSI = foundFactory
92                 .isModuleImplementingServiceInterface(expectedServiceInterface);
93         if (implementsSI == false) {
94             String message = format(
95                     "Found module factory does not expose expected service interface. "
96                             + "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
97                             + "attribute %s",
98                     foundFactory.getImplementationName(), foundFactory,
99                     expectedServiceInterface, dependentModuleReadOnlyON,
100                     jmxAttribute);
101             throw new JmxAttributeValidationException(message, jmxAttribute);
102         }
103         synchronized (this) {
104             dependencies.add(moduleIdentifier);
105         }
106     }
107
108     /**
109      * {@inheritDoc}
110      */
111     @Override
112     public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
113             JmxAttribute jmxAttribute) {
114         if (expectedType == null || dependentON == null || jmxAttribute == null) {
115             throw new IllegalArgumentException(format(
116                     "Null parameters not allowed, got {} {} {}", expectedType,
117                     dependentON, jmxAttribute));
118         }
119
120         transactionStatus.checkCommitStarted();
121         transactionStatus.checkNotCommitted();
122
123         ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
124                 dependentON, ObjectNameUtil.TYPE_MODULE);
125         Module module = modulesHolder.findModule(dependentModuleIdentifier,
126                 jmxAttribute);
127         synchronized (this) {
128             dependencies.add(dependentModuleIdentifier);
129         }
130         AutoCloseable instance = module.getInstance();
131         if (instance == null) {
132             String message = format(
133                     "Error while %s resolving instance %s. getInstance() returned null. "
134                             + "Expected type %s , attribute %s", name,
135                     dependentModuleIdentifier, expectedType, jmxAttribute);
136             throw new JmxAttributeValidationException(message, jmxAttribute);
137         }
138         try {
139             T result = expectedType.cast(instance);
140             return result;
141         } catch (ClassCastException e) {
142             String message = format(
143                     "Instance cannot be cast to expected type. Instance class is %s , "
144                             + "expected type %s , attribute %s",
145                     instance.getClass(), expectedType, jmxAttribute);
146             throw new JmxAttributeValidationException(message, e, jmxAttribute);
147         }
148     }
149
150     @Override
151     public int compareTo(DependencyResolverImpl o) {
152         transactionStatus.checkCommitted();
153         return Integer.compare(getMaxDependencyDepth(),
154                 o.getMaxDependencyDepth());
155     }
156
157     private Integer maxDependencyDepth;
158
159     int getMaxDependencyDepth() {
160         if (maxDependencyDepth == null) {
161             throw new IllegalStateException("Dependency depth was not computed");
162         }
163         return maxDependencyDepth;
164     }
165
166     public void countMaxDependencyDepth(DependencyResolverManager manager) {
167         transactionStatus.checkCommitted();
168         if (maxDependencyDepth == null) {
169             maxDependencyDepth = getMaxDepth(this, manager,
170                     new LinkedHashSet<ModuleIdentifier>());
171         }
172     }
173
174     private static int getMaxDepth(DependencyResolverImpl impl,
175             DependencyResolverManager manager,
176             LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
177         int maxDepth = 0;
178         LinkedHashSet<ModuleIdentifier> chainForDetectingCycles2 = new LinkedHashSet<>(
179                 chainForDetectingCycles);
180         chainForDetectingCycles2.add(impl.getName());
181         for (ModuleIdentifier dependencyName : impl.dependencies) {
182             DependencyResolverImpl dependentDRI = manager
183                     .getOrCreate(dependencyName);
184             if (chainForDetectingCycles2.contains(dependencyName)) {
185                 throw new IllegalStateException(format(
186                         "Cycle detected, {} contains {}",
187                         chainForDetectingCycles2, dependencyName));
188             }
189             int subDepth;
190             if (dependentDRI.maxDependencyDepth != null) {
191                 subDepth = dependentDRI.maxDependencyDepth;
192             } else {
193                 subDepth = getMaxDepth(dependentDRI, manager,
194                         chainForDetectingCycles2);
195                 dependentDRI.maxDependencyDepth = subDepth;
196             }
197             if (subDepth + 1 > maxDepth) {
198                 maxDepth = subDepth + 1;
199             }
200         }
201         impl.maxDependencyDepth = maxDepth;
202         return maxDepth;
203     }
204
205     @Override
206     public ModuleIdentifier getIdentifier() {
207         return name;
208     }
209 }