Merge "Add reverse() method in Edge and Path classes"
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / dependencyresolver / DependencyResolverImpl.java
index 065a0f843f501cdb7e2a4230c9cc0b72caf31f3c..c229450c30138584e615e552843c1b0f10581dca 100644 (file)
@@ -8,14 +8,22 @@
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
 import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.IdentityAttributeRef;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
+import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.annotation.concurrent.GuardedBy;
 import javax.management.ObjectName;
@@ -31,52 +39,64 @@ import static java.lang.String.format;
  * during validation. Tracks dependencies for ordering purposes.
  */
 final class DependencyResolverImpl implements DependencyResolver,
-       Comparable<DependencyResolverImpl> {
+        Comparable<DependencyResolverImpl> {
+    private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class);
+
     private final ModulesHolder modulesHolder;
     private final ModuleIdentifier name;
     private final TransactionStatus transactionStatus;
     @GuardedBy("this")
     private final Set<ModuleIdentifier> dependencies = new HashSet<>();
+    private final ServiceReferenceReadableRegistry readableRegistry;
+    private final CodecRegistry codecRegistry;
 
     DependencyResolverImpl(ModuleIdentifier currentModule,
-            TransactionStatus transactionStatus, ModulesHolder modulesHolder) {
+                           TransactionStatus transactionStatus, ModulesHolder modulesHolder,
+                           ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
+        this.codecRegistry = codecRegistry;
         this.name = currentModule;
         this.transactionStatus = transactionStatus;
         this.modulesHolder = modulesHolder;
+        this.readableRegistry = readableRegistry;
     }
 
     /**
      * {@inheritDoc}
      */
+    //TODO: check for cycles
     @Override
     public void validateDependency(
             Class<? extends AbstractServiceInterface> expectedServiceInterface,
-            ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) {
+            ObjectName dependentReadOnlyON, JmxAttribute jmxAttribute) {
 
         transactionStatus.checkNotCommitted();
         if (expectedServiceInterface == null) {
             throw new NullPointerException(
                     "Parameter 'expectedServiceInterface' is null");
         }
-        if (jmxAttribute == null)
+        if (jmxAttribute == null) {
             throw new NullPointerException("Parameter 'jmxAttribute' is null");
+        }
 
-        JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON,
-                "is null, " + "expected dependency implementing "
+        JmxAttributeValidationException.checkNotNull(dependentReadOnlyON,
+                "is null, expected dependency implementing "
                         + expectedServiceInterface, jmxAttribute);
 
+
         // check that objectName belongs to this transaction - this should be
         // stripped
         // in DynamicWritableWrapper
         boolean hasTransaction = ObjectNameUtil
-                .getTransactionName(dependentModuleReadOnlyON) != null;
+                .getTransactionName(dependentReadOnlyON) != null;
         JmxAttributeValidationException.checkCondition(
                 hasTransaction == false,
                 format("ObjectName should not contain "
                         + "transaction name. %s set to %s. ", jmxAttribute,
-                        dependentModuleReadOnlyON), jmxAttribute);
+                        dependentReadOnlyON), jmxAttribute);
 
-        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil
+        dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+
+        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil
                 .TYPE_MODULE);
 
         ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
@@ -89,7 +109,7 @@ final class DependencyResolverImpl implements DependencyResolver,
                             + "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
                             + "attribute %s",
                     foundFactory.getImplementationName(), foundFactory,
-                    expectedServiceInterface, dependentModuleReadOnlyON,
+                    expectedServiceInterface, dependentReadOnlyON,
                     jmxAttribute);
             throw new JmxAttributeValidationException(message, jmxAttribute);
         }
@@ -98,23 +118,35 @@ final class DependencyResolverImpl implements DependencyResolver,
         }
     }
 
+    // translate from serviceref to module ON
+    private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
+        if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
+            String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
+            String refName = ObjectNameUtil.getReferenceName(dependentReadOnlyON);
+            dependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name
+                    readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName));
+        }
+        return dependentReadOnlyON;
+    }
+
     /**
      * {@inheritDoc}
      */
+    //TODO: check for cycles
     @Override
-    public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
-            JmxAttribute jmxAttribute) {
-        if (expectedType == null || dependentON == null || jmxAttribute == null) {
+    public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentReadOnlyON,
+                                 JmxAttribute jmxAttribute) {
+        if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) {
             throw new IllegalArgumentException(format(
-                    "Null parameters not allowed, got {} {} {}", expectedType,
-                    dependentON, jmxAttribute));
+                    "Null parameters not allowed, got %s %s %s", expectedType,
+                    dependentReadOnlyON, jmxAttribute));
         }
-
+        dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
         transactionStatus.checkCommitStarted();
         transactionStatus.checkNotCommitted();
 
         ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
-                dependentON, ObjectNameUtil.TYPE_MODULE);
+                dependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
         Module module = modulesHolder.findModule(dependentModuleIdentifier,
                 jmxAttribute);
         synchronized (this) {
@@ -129,8 +161,7 @@ final class DependencyResolverImpl implements DependencyResolver,
             throw new JmxAttributeValidationException(message, jmxAttribute);
         }
         try {
-            T result = expectedType.cast(instance);
-            return result;
+            return expectedType.cast(instance);
         } catch (ClassCastException e) {
             String message = format(
                     "Instance cannot be cast to expected type. Instance class is %s , "
@@ -140,6 +171,33 @@ final class DependencyResolverImpl implements DependencyResolver,
         }
     }
 
+    @Override
+    public <T extends BaseIdentity> Class<? extends T> resolveIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass) {
+        final QName qName = QName.create(identityRef.getqNameOfIdentity());
+        IdentityCodec<?> identityCodec = codecRegistry.getIdentityCodec();
+        Class<? extends BaseIdentity> deserialized = identityCodec.deserialize(qName);
+        if (deserialized == null) {
+            throw new IllegalStateException("Unable to retrieve identity class for " + qName + ", null response from "
+                    + codecRegistry);
+        }
+        if (expectedBaseClass.isAssignableFrom(deserialized)) {
+            return (Class<T>) deserialized;
+        } else {
+            logger.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.",
+                    identityRef, deserialized, expectedBaseClass);
+            throw new IllegalArgumentException("Deserialized identity " + deserialized + " cannot be cast to " + expectedBaseClass);
+        }
+    }
+
+    @Override
+    public <T extends BaseIdentity> void validateIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass, JmxAttribute jmxAttribute) {
+        try {
+            resolveIdentity(identityRef, expectedBaseClass);
+        } catch (Exception e) {
+            throw JmxAttributeValidationException.wrap(e, jmxAttribute);
+        }
+    }
+
     @Override
     public int compareTo(DependencyResolverImpl o) {
         transactionStatus.checkCommitted();
@@ -156,7 +214,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         return maxDependencyDepth;
     }
 
-    public void countMaxDependencyDepth(DependencyResolverManager manager) {
+    void countMaxDependencyDepth(DependencyResolverManager manager) {
         transactionStatus.checkCommitted();
         if (maxDependencyDepth == null) {
             maxDependencyDepth = getMaxDepth(this, manager,
@@ -165,8 +223,8 @@ final class DependencyResolverImpl implements DependencyResolver,
     }
 
     private static int getMaxDepth(DependencyResolverImpl impl,
-            DependencyResolverManager manager,
-            LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
+                                   DependencyResolverManager manager,
+                                   LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
         int maxDepth = 0;
         LinkedHashSet<ModuleIdentifier> chainForDetectingCycles2 = new LinkedHashSet<>(
                 chainForDetectingCycles);
@@ -176,7 +234,7 @@ final class DependencyResolverImpl implements DependencyResolver,
                     .getOrCreate(dependencyName);
             if (chainForDetectingCycles2.contains(dependencyName)) {
                 throw new IllegalStateException(format(
-                        "Cycle detected, {} contains {}",
+                        "Cycle detected, %s contains %s",
                         chainForDetectingCycles2, dependencyName));
             }
             int subDepth;
@@ -199,4 +257,5 @@ final class DependencyResolverImpl implements DependencyResolver,
     public ModuleIdentifier getIdentifier() {
         return name;
     }
+
 }