Registered simple classifier-instance validators 33/30733/8
authorMartin Sunal <msunal@cisco.com>
Fri, 4 Dec 2015 18:49:26 +0000 (19:49 +0100)
committerMartin Sunal <msunal@cisco.com>
Fri, 11 Dec 2015 11:45:38 +0000 (12:45 +0100)
- classifier-instance validators based on renderer's capabilities
- this simple classifier-instance validators are registerd automaticly
if PolicyValidatorRegistry is available

Change-Id: Ie418fb7cebbd38fc25fdb7daed4f6745ac0fbe98
Signed-off-by: Martin Sunal <msunal@cisco.com>
groupbasedpolicy/src/main/config/default-config.xml
groupbasedpolicy/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/EpRendererAugmentationRegistryImplModule.java
groupbasedpolicy/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/GroupbasedpolicyModule.java
groupbasedpolicy/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/PolicyValidatorRegistryModule.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/sf/ClassifierInstanceValidator.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/sf/DataTreeChangeHandler.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/sf/SupportedClassifierDefinitionListener.java
groupbasedpolicy/src/main/yang/groupbasedpolicy-cfg.yang
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/sf/SupportedClassifierDefinitionListenerTest.java

index 09dc05dfc31b69ad4c8452934af346acbf5c6c43..523043cfa386beddb2ce1b50a25e32e179342543 100755 (executable)
                         <name>binding-rpc-broker</name>
                     </rpc-registry>
 
+                    <policy-validator-registry>
+                        <type xmlns:groupbasedpolicy="urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy">groupbasedpolicy:policy-validator-registry</type>
+                        <name>policy-validator-registry</name>
+                    </policy-validator-registry>
                 </module>
                 <module>
                     <type xmlns:groupbasedpolicy="urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy">
@@ -38,7 +42,6 @@
                         <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
                         <name>binding-data-broker</name>
                     </data-broker>
-
                 </module>
                 <module>
                     <type xmlns:groupbasedpolicy="urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy">
@@ -55,7 +58,6 @@
                         <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
                         <name>binding-rpc-broker</name>
                     </rpc-registry>
-
                 </module>
             </modules>
 
@@ -71,8 +73,8 @@
                     </instance>
                 </service>
                 <service>
-                    <type xmlns:epr="urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy">
-                        epr:ep-renderer-augmentation-registry
+                    <type xmlns:groupbasedpolicy="urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy">
+                        groupbasedpolicy:ep-renderer-augmentation-registry
                     </type>
 
                     <instance>
index 3d99ec4037ac5d9a76b2abcc2f04231260789342..97b4eb934802f2c7e140c3e957f7e98f921897ac 100644 (file)
@@ -1,11 +1,15 @@
 package org.opendaylight.controller.config.yang.config.groupbasedpolicy;
 
-import com.google.common.base.Preconditions;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.groupbasedpolicy.endpoint.EndpointRpcRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class EpRendererAugmentationRegistryImplModule extends org.opendaylight.controller.config.yang.config.groupbasedpolicy.AbstractEpRendererAugmentationRegistryImplModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EpRendererAugmentationRegistryImplModule.class);
+
     public EpRendererAugmentationRegistryImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
@@ -21,10 +25,12 @@ public class EpRendererAugmentationRegistryImplModule extends org.opendaylight.c
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        final DataBroker dataProvider = Preconditions.checkNotNull(getDataBrokerDependency());
-        final RpcProviderRegistry rpcRegistry = Preconditions.checkNotNull(getRpcRegistryDependency());
+        final DataBroker dataProvider = getDataBrokerDependency();
+        final RpcProviderRegistry rpcRegistry = getRpcRegistryDependency();
 
-        return new EndpointRpcRegistry(dataProvider, rpcRegistry);
+        EndpointRpcRegistry endpointRpcRegistry = new EndpointRpcRegistry(dataProvider, rpcRegistry);
+        LOG.info("{} successfully started.", EpRendererAugmentationRegistryImplModule.class.getCanonicalName());
+        return endpointRpcRegistry;
     }
 
 }
index 2086f4c1828e1a40c811dfd4bb78eb4a9ea380ff..e649597447e03bc79134dd5daa448e7d60afb006 100644 (file)
@@ -1,8 +1,8 @@
 package org.opendaylight.controller.config.yang.config.groupbasedpolicy;
 
-import com.google.common.base.Preconditions;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.groupbasedpolicy.api.PolicyValidatorRegistry;
 import org.opendaylight.groupbasedpolicy.sf.SubjectFeatureDefinitionProvider;
 import org.opendaylight.groupbasedpolicy.sf.SupportedActionDefinitionListener;
 import org.opendaylight.groupbasedpolicy.sf.SupportedClassifierDefinitionListener;
@@ -33,22 +33,13 @@ public class GroupbasedpolicyModule extends org.opendaylight.controller.config.y
      */
     @Override
     public java.lang.AutoCloseable createInstance() {
-        final DataBroker dataProvider = Preconditions.checkNotNull(getDataBrokerDependency());
+        DataBroker dataProvider = getDataBrokerDependency();
+        PolicyValidatorRegistry validatorRegistry = getPolicyValidatorRegistryDependency();
+
         try {
-            return new AutoCloseable() {
-
-                SubjectFeatureDefinitionProvider sfdp = new SubjectFeatureDefinitionProvider(dataProvider);
-                SupportedClassifierDefinitionListener supportedClassifierDefinitionListener =
-                        new SupportedClassifierDefinitionListener(dataProvider);
-                SupportedActionDefinitionListener supportedActionDefinitionListener =
-                        new SupportedActionDefinitionListener(dataProvider);
-                @Override
-                public void close() throws Exception {
-                    sfdp.close();
-                    supportedClassifierDefinitionListener.close();
-                    supportedActionDefinitionListener.close();
-                }
-            };
+            Instance instance = new Instance(dataProvider, validatorRegistry);
+            LOG.info("{} successfully started.", GroupbasedpolicyModule.class.getCanonicalName());
+            return instance;
         } catch (TransactionCommitFailedException e) {
             LOG.error(
                     "Error creating instance of SubjectFeatureDefinitionProvider; Subject Feature Definitions were not put to Datastore");
@@ -56,4 +47,24 @@ public class GroupbasedpolicyModule extends org.opendaylight.controller.config.y
         }
     }
 
+    private static class Instance implements AutoCloseable {
+
+        private final SubjectFeatureDefinitionProvider sfdp;
+        private final SupportedClassifierDefinitionListener supportedClassifierDefinitionListener;
+        private final SupportedActionDefinitionListener supportedActionDefinitionListener;
+
+        Instance(DataBroker dataProvider, PolicyValidatorRegistry validatorRegistry) throws TransactionCommitFailedException {
+            sfdp = new SubjectFeatureDefinitionProvider(dataProvider);
+            supportedClassifierDefinitionListener = new SupportedClassifierDefinitionListener(dataProvider, validatorRegistry);
+            supportedActionDefinitionListener = new SupportedActionDefinitionListener(dataProvider);
+        }
+
+        @Override
+        public void close() throws Exception {
+            sfdp.close();
+            supportedClassifierDefinitionListener.close();
+            supportedActionDefinitionListener.close();
+        }
+    }
+
 }
index fc8b92d85e1157eed0ece6c67376cba0cb614f94..57e8abcc00b4cc2512a13dc03a94ab27169cba35 100644 (file)
@@ -1,10 +1,14 @@
 package org.opendaylight.controller.config.yang.config.groupbasedpolicy;
 
-import com.google.common.base.Preconditions;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class PolicyValidatorRegistryModule extends org.opendaylight.controller.config.yang.config.groupbasedpolicy.AbstractPolicyValidatorRegistryModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PolicyValidatorRegistryModule.class);
+
     public PolicyValidatorRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
@@ -20,9 +24,11 @@ public class PolicyValidatorRegistryModule extends org.opendaylight.controller.c
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        final DataBroker dataProvider = Preconditions.checkNotNull(getDataBrokerDependency());
+        final DataBroker dataProvider = getDataBrokerDependency();
 
-        return new PolicyResolver(dataProvider);
+        PolicyResolver policyResolver = new PolicyResolver(dataProvider);
+        LOG.info("{} successfully started.", PolicyValidatorRegistryModule.class.getCanonicalName());
+        return policyResolver;
     }
 
 }
index c003649d1141f6e66f349d4b752600c09318c3ec..a00830b4e63223280f22d5861b2f24406a896b40 100755 (executable)
@@ -327,7 +327,8 @@ public class PolicyResolver implements PolicyValidatorRegistry, AutoCloseable {
             for (Validator<ActionInstance> actionInstanceValidator : actionInstanceValidators) {
                 ValidationResult validationResult = actionInstanceValidator.validate(actionInstance);
                 if (!validationResult.isValid()) {
-                    LOG.error("ActionInstance {} is not valid!", actionInstance.getName());
+                    LOG.error("ActionInstance {} is not valid! {}", actionInstance.getName().getValue(),
+                            validationResult.getMessage());
                     return false;
                 }
             }
@@ -352,7 +353,8 @@ public class PolicyResolver implements PolicyValidatorRegistry, AutoCloseable {
             for (Validator<ClassifierInstance> classifierInstanceValidator : classifierInstanceValidators) {
                 ValidationResult validationResult = classifierInstanceValidator.validate(classifierInstance);
                 if (!validationResult.isValid()) {
-                    LOG.error("ClassifierInstance {} is not valid!", classifierInstance.getName());
+                    LOG.error("ClassifierInstance {} is not valid! {}", classifierInstance.getName().getValue(),
+                            validationResult.getMessage());
                     return false;
                 }
             }
index d54d46c55fe51f8de7b49dd1293a65659eadfb26..5babe027d24b3f28c085ab9a075936d73afdc586 100755 (executable)
@@ -15,10 +15,19 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opendaylight.groupbasedpolicy.api.ValidationResult;
+import org.opendaylight.groupbasedpolicy.api.Validator;
+import org.opendaylight.groupbasedpolicy.dto.ValidationResultBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.parameter.value.RangeValue;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.parameters.type.ParameterType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.parameters.type.parameter.type.Int;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.parameters.type.parameter.type.Range;
@@ -34,55 +43,72 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 
-public class ClassifierInstanceValidator {
+public class ClassifierInstanceValidator implements Validator<ClassifierInstance> {
 
     private static final Logger LOG = LoggerFactory.getLogger(ClassifierInstanceValidator.class);
     private final Map<ParameterName, Optional<ParameterType>> parameterByName = new HashMap<>();
+    private final ClassifierDefinitionId classifierDefinitionId;
+    private final ClassifierDefinitionId parentClassifierDefinitionId;
+    private final RendererName rendererName;
+    private ClassifierInstanceValidator parentValidator;
+
+    public ClassifierInstanceValidator(SupportedClassifierDefinition constraint, RendererName rendererName) {
+        this.rendererName = checkNotNull(rendererName);
+        classifierDefinitionId = checkNotNull(constraint.getClassifierDefinitionId());
+        parentClassifierDefinitionId = constraint.getParentClassifierDefinitionId();
+        if (constraint.getSupportedParameterValues() != null) {
+            for (SupportedParameterValues supportedParams : constraint.getSupportedParameterValues()) {
+                ParameterName parameterName = checkNotNull(supportedParams.getParameterName());
+                ParameterType parameterType = supportedParams.getParameterType();
+                parameterByName.put(parameterName, Optional.fromNullable(parameterType));
+            }
+        }
+    }
 
-    public ClassifierInstanceValidator(SupportedClassifierDefinition constraint) {
-        for (SupportedParameterValues supportedParams : constraint.getSupportedParameterValues()) {
-            ParameterName parameterName = checkNotNull(supportedParams.getParameterName());
-            ParameterType parameterType = supportedParams.getParameterType();
-            parameterByName.put(parameterName, Optional.fromNullable(parameterType));
+    @Override
+    public ValidationResult validate(ClassifierInstance ci) {
+        for (ParameterValue param : ci.getParameterValue()) {
+            ValidationResult validationResult = validate(param, ci.getName());
+            if (!validationResult.isValid()) {
+                return validationResult;
+            }
         }
+        return new ValidationResultBuilder().success().build();
     }
 
-    public boolean validate(ClassifierInstance ci) {
-        List<ParameterValue> params = ci.getParameterValue();
-        for (ParameterValue param : params) {
-            ParameterName paramName = param.getName();
-            Optional<ParameterType> potentialParamConstraint = parameterByName.get(paramName);
-            if (potentialParamConstraint == null) {
-                LOG.info("Parameter {} with value {} is not supported.", paramName, param);
-                return false;
+    public ValidationResult validate(ParameterValue param, ClassifierName ciName) {
+        ParameterName paramName = param.getName();
+        Optional<ParameterType> potentialParamConstraint = parameterByName.get(paramName);
+        if (potentialParamConstraint == null) {
+            // unknown parameter for this validator - let's try validate in parent
+            if (parentValidator != null) {
+                return parentValidator.validate(param, ciName);
             }
-            if (!potentialParamConstraint.isPresent()) {
-                LOG.info("There is no constraint for parameter {}. \nTherefore the parameter is considered as valid.",
-                        param);
-                continue;
+            return createFailedResult(ciName, param, "is not supported");
+        }
+        if (!potentialParamConstraint.isPresent()) {
+            LOG.info("There is no constraint for parameter {}. \nTherefore the parameter is considered as valid.",
+                    param);
+            return new ValidationResultBuilder().success().build();
+        }
+        ParameterType paramConstraint = potentialParamConstraint.get();
+        if (paramConstraint instanceof Int) {
+            boolean paramValid = isParamValid(param, (Int) paramConstraint);
+            if (!paramValid) {
+                return createFailedResultForNotValidParam(ciName, param);
             }
-            ParameterType paramConstraint = potentialParamConstraint.get();
-            if (paramConstraint instanceof Int) {
-                boolean paramValid = isParamValid(param, (Int) paramConstraint);
-                if (!paramValid) {
-                    LOG.info("Parameter {} with value {} is not valid.", paramName, param);
-                    return false;
-                }
-            } else if (paramConstraint instanceof Range) {
-                boolean paramValid = isParamValid(param, (Range) paramConstraint);
-                if (!paramValid) {
-                    LOG.info("Parameter {} with value {} is not valid.", paramName, param);
-                    return false;
-                }
-            } else if (paramConstraint instanceof String) {
-                boolean paramValid = isParamValid(param, (String) paramConstraint);
-                if (!paramValid) {
-                    LOG.info("Parameter {} with value {} is not valid.", paramName, param);
-                    return false;
-                }
+        } else if (paramConstraint instanceof Range) {
+            boolean paramValid = isParamValid(param, (Range) paramConstraint);
+            if (!paramValid) {
+                return createFailedResultForNotValidParam(ciName, param);
+            }
+        } else if (paramConstraint instanceof String) {
+            boolean paramValid = isParamValid(param, (String) paramConstraint);
+            if (!paramValid) {
+                return createFailedResultForNotValidParam(ciName, param);
             }
         }
-        return true;
+        return new ValidationResultBuilder().success().build();
     }
 
     private boolean isParamValid(ParameterValue param, Int constraint) {
@@ -133,10 +159,60 @@ public class ClassifierInstanceValidator {
         return false;
     }
 
-    public Set<ParameterName> getSupportedParameters() {
+    private ValidationResult createFailedResultForNotValidParam(ClassifierName ciName, ParameterValue param) {
+        return createFailedResult(ciName, param, "is not valid");
+    }
+
+    private ValidationResult createFailedResult(ClassifierName ciName, ParameterValue param, java.lang.String cause) {
+        StringBuilder sb = new StringBuilder("Error in classifier-instance ").append(ciName.getValue())
+            .append(". Parameter ")
+            .append(param.getName().getValue())
+            .append(" with value ");
+        if (param.getIntValue() != null) {
+            sb.append(param.getIntValue());
+        } else if (param.getRangeValue() != null) {
+            RangeValue rangeValue = param.getRangeValue();
+            sb.append("min:").append(rangeValue.getMin()).append(" max:").append(rangeValue.getMax());
+        } else if (param.getStringValue() != null) {
+            sb.append(param.getStringValue());
+        }
+        sb.append(" ").append(cause).append(".").toString();
+        return new ValidationResultBuilder().failed().setMessage(sb.toString()).build();
+    }
+
+    public boolean containsParamsForValidation() {
+        for (Optional<ParameterType> paramValue : parameterByName.values()) {
+            if (paramValue.isPresent()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public @Nonnull RendererName getRendererName() {
+        return rendererName;
+    }
+
+    public @Nonnull Set<ParameterName> getSupportedParameters() {
         return parameterByName.keySet();
     }
 
+    public @Nonnull ClassifierDefinitionId getClassifierDefinitionId() {
+        return classifierDefinitionId;
+    }
+
+    public @Nullable ClassifierDefinitionId getParentClassifierDefinitionId() {
+        return parentClassifierDefinitionId;
+    }
+
+    public @Nullable Validator<ClassifierInstance> getParentValidator() {
+        return parentValidator;
+    }
+
+    public void setParentValidator(@Nullable ClassifierInstanceValidator parentValidator) {
+        this.parentValidator = parentValidator;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/sf/DataTreeChangeHandler.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/sf/DataTreeChangeHandler.java
new file mode 100644 (file)
index 0000000..6dd6a52
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.sf;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * The purpose of this class is to eliminate boilerplate code used in most of
+ * {@link DataTreeChangeListener} implementations.
+ * 
+ * @param <T>
+ */
+public abstract class DataTreeChangeHandler<T extends DataObject> implements DataTreeChangeListener<T>, AutoCloseable {
+
+    protected final DataBroker dataProvider;
+    protected final ListenerRegistration<DataTreeChangeHandler<T>> registeredListener;
+
+    /**
+     * Registers {@link DataTreeChangeListener} for {@code pointOfInterest} by using
+     * {@code dataProvider}
+     * 
+     * @param dataProvider cannot be {@code null}
+     * @param pointOfInterest cannot be {@code null}
+     * @throws NullPointerException if at least one paramter is {@code null}
+     */
+    protected DataTreeChangeHandler(DataBroker dataProvider, DataTreeIdentifier<T> pointOfInterest) {
+        this.dataProvider = checkNotNull(dataProvider);
+        registeredListener = dataProvider.registerDataTreeChangeListener(checkNotNull(pointOfInterest), this);
+    }
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
+        for (DataTreeModification<T> change : changes) {
+            DataObjectModification<T> rootNode = change.getRootNode();
+            InstanceIdentifier<T> rootIdentifier = change.getRootPath().getRootIdentifier();
+            switch (rootNode.getModificationType()) {
+                case WRITE:
+                    onWrite(rootNode, rootIdentifier);
+                    break;
+                case DELETE:
+                    onDelete(rootNode, rootIdentifier);
+                    break;
+                case SUBTREE_MODIFIED:
+                    onSubreeModified(rootNode, rootIdentifier);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Handles case where {@link DataObjectModification#getModificationType()} is
+     * {@link ModificationType#WRITE}. <br>
+     * <b>Parameters of this method are never {@code null}.</b>
+     * 
+     * @param rootNode represents {@link DataObjectModification} as result of
+     *        {@link DataTreeModification#getRootNode()}
+     * @param rootIdentifier represents {@link InstanceIdentifier} obtained from result of
+     *        {@link DataTreeModification#getRootPath()}
+     */
+    protected abstract void onWrite(DataObjectModification<T> rootNode, InstanceIdentifier<T> rootIdentifier);
+
+    /**
+     * Handles case where {@link DataObjectModification#getModificationType()} is
+     * {@link ModificationType#DELETE}. <br>
+     * <b>Parameters of this method are never {@code null}.</b>
+     * 
+     * @param rootNode represents {@link DataObjectModification} as result of
+     *        {@link DataTreeModification#getRootNode()}
+     * @param rootIdentifier represents {@link InstanceIdentifier} obtained from result of
+     *        {@link DataTreeModification#getRootPath()}
+     */
+    protected abstract void onDelete(DataObjectModification<T> rootNode, InstanceIdentifier<T> rootIdentifier);
+
+    /**
+     * Handles case where {@link DataObjectModification#getModificationType()} is
+     * {@link ModificationType#SUBTREE_MODIFIED}. <br>
+     * <b>Parameters of this method are never {@code null}.</b>
+     * 
+     * @param rootNode represents {@link DataObjectModification} as result of
+     *        {@link DataTreeModification#getRootNode()}
+     * @param rootIdentifier represents {@link InstanceIdentifier} obtained from result of
+     *        {@link DataTreeModification#getRootPath()}
+     */
+    protected abstract void onSubreeModified(DataObjectModification<T> rootNode, InstanceIdentifier<T> rootIdentifier);
+
+    @Override
+    public void close() throws Exception {
+        registeredListener.close();
+    }
+
+}
index 6ccaa787f61dff058ab39ddc42f3fd80feabd613..f396e4121a53851c64d065f5d4d4db08aee0c81d 100644 (file)
@@ -8,23 +8,17 @@
 
 package org.opendaylight.groupbasedpolicy.sf;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
-import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.api.PolicyValidatorRegistry;
 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
@@ -32,143 +26,195 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.Capabilities;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedClassifierDefinition;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.SetMultimap;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
 
-public class SupportedClassifierDefinitionListener
-        implements DataTreeChangeListener<SupportedClassifierDefinition>, AutoCloseable {
+public class SupportedClassifierDefinitionListener extends DataTreeChangeHandler<SupportedClassifierDefinition> {
 
     private static final Logger LOG = LoggerFactory.getLogger(SupportedClassifierDefinitionListener.class);
 
-    private final DataBroker dataProvider;
-    private final ListenerRegistration<SupportedClassifierDefinitionListener> registration;
-    @VisibleForTesting
-    final SetMultimap<ClassifierDefinitionId, InstanceIdentifier<SupportedClassifierDefinition>> supportedCdIidByCdId =
-            HashMultimap.create();
     @VisibleForTesting
-    final Map<InstanceIdentifier<SupportedClassifierDefinition>, ClassifierInstanceValidator> ciValidatorBySupportedCdIid =
-            new HashMap<>();
-
-    public SupportedClassifierDefinitionListener(DataBroker dataProvider) {
-        this.dataProvider = checkNotNull(dataProvider);
-        registration =
-                dataProvider.registerDataTreeChangeListener(
-                        new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
-                                InstanceIdentifier.builder(Renderers.class)
-                                    .child(Renderer.class)
-                                    .child(Capabilities.class)
-                                    .child(SupportedClassifierDefinition.class)
-                                    .build()),
-                        this);
+    final Table<RendererName, ClassifierDefinitionId, ClassifierInstanceValidator> validatorByRendererAndCd =
+            HashBasedTable.create();
+    private final PolicyValidatorRegistry validatorRegistry;
+
+    public SupportedClassifierDefinitionListener(DataBroker dataProvider, PolicyValidatorRegistry validatorRegistry) {
+        super(dataProvider,
+                new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                        InstanceIdentifier.builder(Renderers.class)
+                            .child(Renderer.class)
+                            .child(Capabilities.class)
+                            .child(SupportedClassifierDefinition.class)
+                            .build()));
+        this.validatorRegistry = validatorRegistry;
+        if (validatorRegistry == null) {
+            LOG.info(
+                    "{} service was NOT found. Automatic registration of simple classifier-instance validators is NOT available for renderers.",
+                    PolicyValidatorRegistry.class.getCanonicalName());
+        } else {
+            LOG.info(
+                    "{} service was found. Automatic registration of simple classifier-instance validators is available for renderers.",
+                    PolicyValidatorRegistry.class.getCanonicalName());
+        }
     }
 
     @Override
-    public void onDataTreeChanged(Collection<DataTreeModification<SupportedClassifierDefinition>> changes) {
-        for (DataTreeModification<SupportedClassifierDefinition> change : changes) {
-            DataObjectModification<SupportedClassifierDefinition> rootNode = change.getRootNode();
-            InstanceIdentifier<SupportedClassifierDefinition> rootIdentifier = change.getRootPath().getRootIdentifier();
-            switch (rootNode.getModificationType()) {
-                case WRITE:
-                    ClassifierDefinitionId classifierDefinitionId = rootNode.getDataAfter().getClassifierDefinitionId();
-                    if (containsParameters(rootNode.getDataAfter())) {
-                        ClassifierInstanceValidator ciValidator =
-                                new ClassifierInstanceValidator(rootNode.getDataAfter());
-                        ciValidatorBySupportedCdIid.put(rootIdentifier, ciValidator);
-                        // TODO register validator to Policy Resolver service
-                    }
-                    supportedCdIidByCdId.put(classifierDefinitionId, rootIdentifier);
-                    putOrRemoveClassifierDefinitionInOperDs(classifierDefinitionId);
-                    break;
-                case DELETE:
-                    classifierDefinitionId = rootNode.getDataBefore().getClassifierDefinitionId();
-                    // TODO unregister validator from Policy Resolver service
-                    supportedCdIidByCdId.remove(classifierDefinitionId, rootIdentifier);
-                    ciValidatorBySupportedCdIid.remove(rootIdentifier);
-                    putOrRemoveClassifierDefinitionInOperDs(classifierDefinitionId);
-                    break;
-                case SUBTREE_MODIFIED:
-                    classifierDefinitionId = rootNode.getDataAfter().getClassifierDefinitionId();
-                    if (containsParameters(rootNode.getDataAfter())) {
-                        ClassifierInstanceValidator ciValidator =
-                                new ClassifierInstanceValidator(rootNode.getDataAfter());
-                        ClassifierInstanceValidator oldCiValidator =
-                                ciValidatorBySupportedCdIid.put(rootIdentifier, ciValidator);
-                        // TODO unregister old validator from Policy Resolver service and register
-                        // new one
-                    }
-                    putOrRemoveClassifierDefinitionInOperDs(classifierDefinitionId);
-                    break;
+    protected void onWrite(DataObjectModification<SupportedClassifierDefinition> rootNode,
+            InstanceIdentifier<SupportedClassifierDefinition> createdSupportedCdIid) {
+        SupportedClassifierDefinition createdSupportedCd = rootNode.getDataAfter();
+        RendererName rendererName = createdSupportedCdIid.firstKeyOf(Renderer.class).getName();
+        ClassifierInstanceValidator ciValidator = new ClassifierInstanceValidator(createdSupportedCd, rendererName);
+        setParentValidators(ciValidator, false);
+        ClassifierDefinitionId cdId = createdSupportedCd.getClassifierDefinitionId();
+        validatorByRendererAndCd.put(rendererName, cdId, ciValidator);
+        if (validatorRegistry != null) {
+            validatorRegistry.register(cdId, ciValidator);
+        }
+        putOrRemoveClassifierDefinitionInOperDs(cdId, getAllSupportedParams(cdId));
+    }
+
+    @Override
+    protected void onDelete(DataObjectModification<SupportedClassifierDefinition> rootNode,
+            InstanceIdentifier<SupportedClassifierDefinition> removedSupportedCdIid) {
+        SupportedClassifierDefinition removedSupportedCd = rootNode.getDataBefore();
+        ClassifierDefinitionId cdId = removedSupportedCd.getClassifierDefinitionId();
+        RendererName rendererName = removedSupportedCdIid.firstKeyOf(Renderer.class).getName();
+        ClassifierInstanceValidator removedCiValidator = validatorByRendererAndCd.remove(rendererName, cdId);
+        if (validatorRegistry != null) {
+            validatorRegistry.unregister(cdId, removedCiValidator);
+        }
+        setParentValidators(removedCiValidator, true);
+        putOrRemoveClassifierDefinitionInOperDs(cdId, getAllSupportedParams(cdId));
+    }
+
+    @Override
+    protected void onSubreeModified(DataObjectModification<SupportedClassifierDefinition> rootNode,
+            InstanceIdentifier<SupportedClassifierDefinition> modifiedSupportedCdIid) {
+        SupportedClassifierDefinition beforeSupportedCd = rootNode.getDataBefore();
+        ClassifierDefinitionId cdId = beforeSupportedCd.getClassifierDefinitionId();
+        RendererName rendererName = modifiedSupportedCdIid.firstKeyOf(Renderer.class).getName();
+        ClassifierInstanceValidator oldCiValidator = validatorByRendererAndCd.remove(rendererName, cdId);
+        if (validatorRegistry != null) {
+            validatorRegistry.unregister(cdId, oldCiValidator);
+        }
+        SupportedClassifierDefinition afterSupportedCd = rootNode.getDataAfter();
+        ClassifierInstanceValidator newCiValidator = new ClassifierInstanceValidator(afterSupportedCd, rendererName);
+        setParentValidators(newCiValidator, false);
+        validatorByRendererAndCd.put(rendererName, cdId, newCiValidator);
+        if (validatorRegistry != null) {
+            validatorRegistry.register(cdId, newCiValidator);
+        }
+        putOrRemoveClassifierDefinitionInOperDs(cdId, getAllSupportedParams(cdId));
+    }
+
+    @VisibleForTesting
+    void setParentValidators(ClassifierInstanceValidator ciValidator, boolean setParentToNull) {
+        if (ciValidator.getParentClassifierDefinitionId() != null && !setParentToNull) {
+            ClassifierInstanceValidator parentCiValidator = validatorByRendererAndCd.get(ciValidator.getRendererName(),
+                    ciValidator.getParentClassifierDefinitionId());
+            if (parentCiValidator != null) {
+                ciValidator.setParentValidator(parentCiValidator);
+            }
+        }
+        for (ClassifierInstanceValidator existingCiValidator : getValidatorsWithParentCdForRenderer(
+                ciValidator.getClassifierDefinitionId(), ciValidator.getRendererName())) {
+            if (setParentToNull) {
+                existingCiValidator.setParentValidator(null);
+            } else {
+                existingCiValidator.setParentValidator(ciValidator);
             }
         }
     }
 
-    private boolean containsParameters(SupportedClassifierDefinition supportedClassifierDefinition) {
-        return supportedClassifierDefinition.getSupportedParameterValues() != null
-                && !supportedClassifierDefinition.getSupportedParameterValues().isEmpty();
+    @VisibleForTesting
+    Collection<ClassifierInstanceValidator> getValidatorsWithParentCdForRenderer(
+            final ClassifierDefinitionId parentCdId, RendererName renderer) {
+        return Collections2.filter(validatorByRendererAndCd.row(renderer).values(),
+                new Predicate<ClassifierInstanceValidator>() {
+
+                    @Override
+                    public boolean apply(ClassifierInstanceValidator ciValidator) {
+                        if (parentCdId.equals(ciValidator.getParentClassifierDefinitionId())) {
+                            return true;
+                        }
+                        return false;
+                    }
+                });
     }
 
-    private void putOrRemoveClassifierDefinitionInOperDs(ClassifierDefinitionId classifierDefinitionId) {
+    @VisibleForTesting
+    List<ParameterName> getAllSupportedParams(final ClassifierDefinitionId cdId) {
+        return FluentIterable.from(validatorByRendererAndCd.column(cdId).values())
+            .transformAndConcat(new Function<ClassifierInstanceValidator, Set<ParameterName>>() {
+
+                @Override
+                public Set<ParameterName> apply(ClassifierInstanceValidator input) {
+                    return input.getSupportedParameters();
+                }
+            })
+            .toList();
+    }
+
+    @VisibleForTesting
+    void putOrRemoveClassifierDefinitionInOperDs(ClassifierDefinitionId cdId, List<ParameterName> supportedParams) {
         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
-        ClassifierDefinition cd = createClassifierDefinitionWithUnionOfParams(classifierDefinitionId, rwTx);
+        Optional<ClassifierDefinition> potentialCdFromConfDs = DataStoreHelper
+            .readFromDs(LogicalDatastoreType.CONFIGURATION, IidFactory.classifierDefinitionIid(cdId), rwTx);
+        if (!potentialCdFromConfDs.isPresent()) {
+            LOG.error("Classifier-definition with ID {} does not exist in CONF datastore.", cdId);
+            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(cdId),
+                    rwTx);
+            DataStoreHelper.submitToDs(rwTx);
+            return;
+        }
+        ClassifierDefinition cd =
+                createClassifierDefinitionWithUnionOfParams(potentialCdFromConfDs.get(), supportedParams);
         if (cd != null) {
-            rwTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(classifierDefinitionId), cd);
+            rwTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(cdId), cd);
         } else {
-            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
-                    IidFactory.classifierDefinitionIid(classifierDefinitionId), rwTx);
+            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(cdId),
+                    rwTx);
         }
         DataStoreHelper.submitToDs(rwTx);
     }
 
     @VisibleForTesting
-    ClassifierDefinition createClassifierDefinitionWithUnionOfParams(ClassifierDefinitionId classifierDefinitionId,
-            ReadTransaction rTx) {
-        Optional<ClassifierDefinition> potentialCdFromDs = DataStoreHelper.readFromDs(
-                LogicalDatastoreType.CONFIGURATION, IidFactory.classifierDefinitionIid(classifierDefinitionId), rTx);
-        if (!potentialCdFromDs.isPresent()) {
-            LOG.error("Classifier-definition with ID {} does not exist in CONF datastore.", classifierDefinitionId);
-            return null;
-        }
-        ClassifierDefinition cdFromDs = potentialCdFromDs.get();
-        Set<InstanceIdentifier<SupportedClassifierDefinition>> supportedCdIids =
-                supportedCdIidByCdId.get(classifierDefinitionId);
-        if (supportedCdIids.isEmpty()) {
-            LOG.debug("Classifier-definition with ID {} is not supported by any renderer.", classifierDefinitionId);
+    static ClassifierDefinition createClassifierDefinitionWithUnionOfParams(ClassifierDefinition cd,
+            List<ParameterName> supportedParams) {
+        if (supportedParams == null || supportedParams.isEmpty()) {
+            LOG.debug("Classifier-definition with ID {} is not supported by any renderer.", cd.getId().getValue());
             return null;
         }
-        if (cdFromDs.getParameter() == null || cdFromDs.getParameter().isEmpty()) {
-            LOG.debug("Classifier-definition with ID {} does not contain any parameter", classifierDefinitionId);
-            return cdFromDs;
+        if (cd.getParameter() == null || cd.getParameter().isEmpty()) {
+            LOG.trace("Classifier-definition with ID {} does not contain any parameter in CONF datastore.",
+                    cd.getId().getValue());
+            return cd;
         }
         List<Parameter> params = new ArrayList<>();
-        for (InstanceIdentifier<SupportedClassifierDefinition> supportedCdIid : supportedCdIids) {
-            ClassifierInstanceValidator ciValidator = ciValidatorBySupportedCdIid.get(supportedCdIid);
-            Set<ParameterName> supportedParams = ciValidator.getSupportedParameters();
-            for (ParameterName supportedParamName : supportedParams) {
-                for (Parameter param : cdFromDs.getParameter()) {
-                    if (param.getName().equals(supportedParamName)) {
-                        params.add(param);
-                    }
+        for (ParameterName supportedParam : supportedParams) {
+            for (Parameter param : cd.getParameter()) {
+                if (param.getName().equals(supportedParam)) {
+                    params.add(param);
                 }
             }
         }
-        ClassifierDefinitionBuilder cdBuilder = new ClassifierDefinitionBuilder(cdFromDs);
+        ClassifierDefinitionBuilder cdBuilder = new ClassifierDefinitionBuilder(cd);
         return cdBuilder.setParameter(params).build();
     }
 
-    @Override
-    public void close() throws Exception {
-        registration.close();
-    }
-
 }
index 59131ae86d96849cf6f1a5ea5229ca065c097e80..a9c961a2b43636342bdc8cf9f3cffe5fa1b08b97 100644 (file)
@@ -9,7 +9,7 @@
 module groupbasedpolicy-cfg {
     yang-version 1;
     namespace "urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy";
-    prefix "groupbasedpolicy-cfg";
+    prefix "gbpcfg";
 
     import config { prefix config; revision-date 2013-04-05; }
     import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
@@ -82,6 +82,14 @@ module groupbasedpolicy-cfg {
                     }
                 }
             }
+            // EpRendererAugmentationRegistry service
+            container policy-validator-registry {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity policy-validator-registry;
+                    }
+                }
+            }
         }
         case policy-validator-registry-impl {
             when "/config:modules/config:module/config:type = 'policy-validator-registry-impl'";
index 1eff017414f33793038725bd9f23b7fd40ea166b..6813988a84ea7c7f45a0cc9bbe9a361031895388 100755 (executable)
@@ -1,11 +1,17 @@
 package org.opendaylight.groupbasedpolicy.sf;
 
+import java.util.Collection;
+import java.util.List;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.api.PolicyValidatorRegistry;
 import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
 import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
 import org.opendaylight.groupbasedpolicy.test.GbpDataBrokerTest;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
@@ -14,78 +20,317 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.Capabilities;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedClassifierDefinition;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedClassifierDefinitionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValues;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValuesBuilder;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 
 public class SupportedClassifierDefinitionListenerTest extends GbpDataBrokerTest {
 
     private SupportedClassifierDefinitionListener listener;
+    private PolicyValidatorRegistry policyValidatorRegistry;
 
     @Before
     public void init() {
-        listener = new SupportedClassifierDefinitionListener(getDataBroker());
+        policyValidatorRegistry = Mockito.mock(PolicyValidatorRegistry.class);
+        listener = new SupportedClassifierDefinitionListener(getDataBroker(), policyValidatorRegistry);
+    }
+
+    @Test
+    public void testSetParentValidators_newValidatorHasParent_parentValidatorExists() {
+        RendererName rendererFoo = new RendererName("Foo");
+        SupportedClassifierDefinition supportedIpProtoPort = new SupportedClassifierDefinitionBuilder()
+            .setClassifierDefinitionId(IpProtoClassifierDefinition.ID).build();
+        ClassifierInstanceValidator rendererFooIpProtoParentValidator =
+                new ClassifierInstanceValidator(supportedIpProtoPort, rendererFoo);
+        listener.validatorByRendererAndCd.put(rendererFoo, IpProtoClassifierDefinition.ID,
+                rendererFooIpProtoParentValidator);
+        SupportedClassifierDefinition supportedL4SrcPort =
+                new SupportedClassifierDefinitionBuilder().setClassifierDefinitionId(L4ClassifierDefinition.ID)
+                    .setParentClassifierDefinitionId(IpProtoClassifierDefinition.ID)
+                    .build();
+        ClassifierInstanceValidator rendererFooL4SrcPortNewValidator =
+                new ClassifierInstanceValidator(supportedL4SrcPort, rendererFoo);
+        listener.validatorByRendererAndCd.put(rendererFoo, L4ClassifierDefinition.ID, rendererFooL4SrcPortNewValidator);
+        listener.setParentValidators(rendererFooL4SrcPortNewValidator, false);
+        Assert.assertEquals(rendererFooIpProtoParentValidator, rendererFooL4SrcPortNewValidator.getParentValidator());
+
+        listener.setParentValidators(rendererFooL4SrcPortNewValidator, true);
+        Assert.assertNull(rendererFooIpProtoParentValidator.getParentValidator());
+    }
+
+    @Test
+    public void testSetParentValidators_newValidatorHasParent_parentValidatorNotExists() {
+        RendererName rendererFoo = new RendererName("Foo");
+        SupportedClassifierDefinition supportedL4SrcPort =
+                new SupportedClassifierDefinitionBuilder().setClassifierDefinitionId(L4ClassifierDefinition.ID)
+                    .setParentClassifierDefinitionId(IpProtoClassifierDefinition.ID)
+                    .build();
+        ClassifierInstanceValidator rendererFooL4SrcPortNewValidator =
+                new ClassifierInstanceValidator(supportedL4SrcPort, rendererFoo);
+        listener.validatorByRendererAndCd.put(rendererFoo, L4ClassifierDefinition.ID, rendererFooL4SrcPortNewValidator);
+
+        listener.setParentValidators(rendererFooL4SrcPortNewValidator, false);
+        Assert.assertNull(rendererFooL4SrcPortNewValidator.getParentValidator());
+
+        SupportedClassifierDefinition supportedIpProtoPort = new SupportedClassifierDefinitionBuilder()
+            .setClassifierDefinitionId(IpProtoClassifierDefinition.ID).build();
+        ClassifierInstanceValidator rendererFooIpProtoParentValidator =
+                new ClassifierInstanceValidator(supportedIpProtoPort, rendererFoo);
+        listener.validatorByRendererAndCd.put(rendererFoo, IpProtoClassifierDefinition.ID,
+                rendererFooIpProtoParentValidator);
+
+        listener.setParentValidators(rendererFooL4SrcPortNewValidator, false);
+        Assert.assertEquals(rendererFooIpProtoParentValidator, rendererFooL4SrcPortNewValidator.getParentValidator());
+
+        listener.setParentValidators(rendererFooL4SrcPortNewValidator, true);
+        Assert.assertNull(rendererFooIpProtoParentValidator.getParentValidator());
+    }
+
+    @Test
+    public void testGetValidatorsWithParentCdForRenderer() {
+        List<SupportedParameterValues> srcPortParam = ImmutableList.of(new SupportedParameterValuesBuilder()
+            .setParameterName(new ParameterName(L4ClassifierDefinition.SRC_PORT_PARAM)).build());
+        SupportedClassifierDefinition supportedL4SrcPort =
+                new SupportedClassifierDefinitionBuilder().setClassifierDefinitionId(L4ClassifierDefinition.ID)
+                    .setParentClassifierDefinitionId(IpProtoClassifierDefinition.ID)
+                    .setSupportedParameterValues(srcPortParam)
+                    .build();
+        RendererName rendererFoo = new RendererName("Foo");
+        ClassifierInstanceValidator rendererFooL4SrcPortValidator =
+                new ClassifierInstanceValidator(supportedL4SrcPort, rendererFoo);
+        listener.validatorByRendererAndCd.put(rendererFoo, supportedL4SrcPort.getClassifierDefinitionId(),
+                rendererFooL4SrcPortValidator);
+        List<SupportedParameterValues> dstPortParam = ImmutableList.of(new SupportedParameterValuesBuilder()
+            .setParameterName(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM)).build());
+        SupportedClassifierDefinition supportedL4DstPort =
+                new SupportedClassifierDefinitionBuilder().setClassifierDefinitionId(L4ClassifierDefinition.ID)
+                    .setParentClassifierDefinitionId(IpProtoClassifierDefinition.ID)
+                    .setSupportedParameterValues(dstPortParam)
+                    .build();
+        RendererName rendererBar = new RendererName("Bar");
+        ClassifierInstanceValidator rendererBarL4DstPortValidator =
+                new ClassifierInstanceValidator(supportedL4DstPort, rendererBar);
+        listener.validatorByRendererAndCd.put(rendererBar, supportedL4DstPort.getClassifierDefinitionId(),
+                rendererBarL4DstPortValidator);
+
+        Collection<ClassifierInstanceValidator> validatorsWithParentIpProtoCdForRendererFoo =
+                listener.getValidatorsWithParentCdForRenderer(IpProtoClassifierDefinition.ID, rendererFoo);
+        Assert.assertNotNull(validatorsWithParentIpProtoCdForRendererFoo);
+        Assert.assertEquals(validatorsWithParentIpProtoCdForRendererFoo.size(), 1);
+        Assert.assertTrue(validatorsWithParentIpProtoCdForRendererFoo.contains(rendererFooL4SrcPortValidator));
+    }
+
+    @Test
+    public void testGetAllSupportedParams() {
+        List<SupportedParameterValues> srcPortParam = ImmutableList.of(new SupportedParameterValuesBuilder()
+            .setParameterName(new ParameterName(L4ClassifierDefinition.SRC_PORT_PARAM)).build());
+        SupportedClassifierDefinition supportedL4SrcPort = new SupportedClassifierDefinitionBuilder()
+            .setClassifierDefinitionId(L4ClassifierDefinition.ID).setSupportedParameterValues(srcPortParam).build();
+        RendererName rendererFoo = new RendererName("Foo");
+        listener.validatorByRendererAndCd.put(rendererFoo, supportedL4SrcPort.getClassifierDefinitionId(),
+                new ClassifierInstanceValidator(supportedL4SrcPort, rendererFoo));
+        List<SupportedParameterValues> dstPortParam = ImmutableList.of(new SupportedParameterValuesBuilder()
+            .setParameterName(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM)).build());
+        SupportedClassifierDefinition supportedL4DstPort = new SupportedClassifierDefinitionBuilder()
+            .setClassifierDefinitionId(L4ClassifierDefinition.ID).setSupportedParameterValues(dstPortParam).build();
+        RendererName rendererBar = new RendererName("Bar");
+        listener.validatorByRendererAndCd.put(rendererBar, supportedL4DstPort.getClassifierDefinitionId(),
+                new ClassifierInstanceValidator(supportedL4DstPort, rendererBar));
+
+        List<ParameterName> allSupportedParams = listener.getAllSupportedParams(L4ClassifierDefinition.ID);
+        Assert.assertTrue(allSupportedParams.contains(new ParameterName(L4ClassifierDefinition.SRC_PORT_PARAM)));
+        Assert.assertTrue(allSupportedParams.contains(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM)));
+    }
+
+    @Test
+    public void testCreateClassifierDefinitionWithUnionOfParams_allSupportedParams() {
+        List<ParameterName> supportedParams =
+                ImmutableList.of(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM));
+        ClassifierDefinition classifierDefinitionWithUnionOfParams = listener
+            .createClassifierDefinitionWithUnionOfParams(EtherTypeClassifierDefinition.DEFINITION, supportedParams);
+        assertEquals(EtherTypeClassifierDefinition.DEFINITION, classifierDefinitionWithUnionOfParams);
+    }
+
+    @Test
+    public void testCreateClassifierDefinitionWithUnionOfParams_emptySupportedParams() {
+        List<ParameterName> supportedParams = ImmutableList.of();
+        ClassifierDefinition classifierDefinitionWithUnionOfParams = listener
+            .createClassifierDefinitionWithUnionOfParams(EtherTypeClassifierDefinition.DEFINITION, supportedParams);
+        Assert.assertNull(classifierDefinitionWithUnionOfParams);
+    }
+
+    @Test
+    public void testCreateClassifierDefinitionWithUnionOfParams_someSupportedParams() {
+        ImmutableList<ParameterName> supportedParams =
+                ImmutableList.of(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM),
+                        new ParameterName(L4ClassifierDefinition.DST_PORT_RANGE_PARAM));
+        ClassifierDefinition classifierDefinitionWithUnionOfParams = listener
+            .createClassifierDefinitionWithUnionOfParams(L4ClassifierDefinition.DEFINITION, supportedParams);
+        ClassifierDefinition expectedCd = new ClassifierDefinitionBuilder(L4ClassifierDefinition.DEFINITION)
+            .setParameter(ImmutableList.<Parameter>of(
+                    getParameterFromDefinition(L4ClassifierDefinition.DEFINITION,
+                            L4ClassifierDefinition.DST_PORT_PARAM),
+                    getParameterFromDefinition(L4ClassifierDefinition.DEFINITION,
+                            L4ClassifierDefinition.DST_PORT_RANGE_PARAM)))
+            .build();
+        assertEquals(expectedCd, classifierDefinitionWithUnionOfParams);
     }
 
     @Test
-    public void testCreateClassifierDefinitionWithUnionOfParams_allParamsSupportedByRenderer() throws Exception {
+    public void testPutOrRemoveClassifierDefinitionInOperDs_cdIsInConfDs_withSupportedParams() throws Exception {
         WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
         wTx.put(LogicalDatastoreType.CONFIGURATION,
                 IidFactory.classifierDefinitionIid(EtherTypeClassifierDefinition.ID),
                 EtherTypeClassifierDefinition.DEFINITION, true);
         wTx.submit().get();
+        List<ParameterName> supportedParams =
+                ImmutableList.of(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM));
 
-        SupportedClassifierDefinition supportedClassifierDefinition = new SupportedClassifierDefinitionBuilder()
-            .setClassifierDefinitionId(EtherTypeClassifierDefinition.ID)
-            .setSupportedParameterValues(
-                    ImmutableList.<SupportedParameterValues>of(new SupportedParameterValuesBuilder()
-                        .setParameterName(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)).build()))
-            .build();
-        Renderer renderer = createRenderer("renderer1");
-        registerSupportedClassifierDefByRenderer(supportedClassifierDefinition, renderer);
+        listener.putOrRemoveClassifierDefinitionInOperDs(EtherTypeClassifierDefinition.ID, supportedParams);
+        Optional<ClassifierDefinition> potentialCd = getDataBroker().newReadOnlyTransaction()
+            .read(LogicalDatastoreType.OPERATIONAL,
+                    IidFactory.classifierDefinitionIid(EtherTypeClassifierDefinition.ID))
+            .get();
+        Assert.assertTrue(potentialCd.isPresent());
+        assertEquals(EtherTypeClassifierDefinition.DEFINITION, potentialCd.get());
+    }
+
+    @Test
+    public void testPutOrRemoveClassifierDefinitionInOperDs_cdIsNotInConfDs_withSupportedParams() throws Exception {
+        List<ParameterName> supportedParams =
+                ImmutableList.of(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM));
 
-        ClassifierDefinition newCd = listener.createClassifierDefinitionWithUnionOfParams(
-                EtherTypeClassifierDefinition.ID, getDataBroker().newReadOnlyTransaction());
-        Assert.assertEquals(EtherTypeClassifierDefinition.DEFINITION, newCd);
+        listener.putOrRemoveClassifierDefinitionInOperDs(EtherTypeClassifierDefinition.ID, supportedParams);
+        Optional<ClassifierDefinition> potentialCd = getDataBroker().newReadOnlyTransaction()
+            .read(LogicalDatastoreType.OPERATIONAL,
+                    IidFactory.classifierDefinitionIid(EtherTypeClassifierDefinition.ID))
+            .get();
+        Assert.assertFalse(potentialCd.isPresent());
     }
 
     @Test
-    public void testCreateClassifierDefinitionWithUnionOfParams_someParamsSupportedByRenderer() throws Exception {
+    public void testPutOrRemoveClassifierDefinitionInOperDs_cdIsInConfDs_emptySupportedParams() throws Exception {
+        WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
+        wTx.put(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.classifierDefinitionIid(EtherTypeClassifierDefinition.ID),
+                EtherTypeClassifierDefinition.DEFINITION, true);
+        wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(EtherTypeClassifierDefinition.ID),
+                EtherTypeClassifierDefinition.DEFINITION, true);
+        wTx.submit().get();
+        List<ParameterName> supportedParams = ImmutableList.of();
+
+        listener.putOrRemoveClassifierDefinitionInOperDs(EtherTypeClassifierDefinition.ID, supportedParams);
+        Optional<ClassifierDefinition> potentialCd = getDataBroker().newReadOnlyTransaction()
+            .read(LogicalDatastoreType.OPERATIONAL,
+                    IidFactory.classifierDefinitionIid(EtherTypeClassifierDefinition.ID))
+            .get();
+        Assert.assertFalse(potentialCd.isPresent());
+    }
+
+    @Test
+    public void testPutOrRemoveClassifierDefinitionInOperDs_cdIsInConfDs_changedSupportedParams() throws Exception {
         WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
         wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.classifierDefinitionIid(L4ClassifierDefinition.ID),
                 L4ClassifierDefinition.DEFINITION, true);
+        wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(L4ClassifierDefinition.ID),
+                L4ClassifierDefinition.DEFINITION, true);
         wTx.submit().get();
+        ImmutableList<ParameterName> supportedParams =
+                ImmutableList.of(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM),
+                        new ParameterName(L4ClassifierDefinition.DST_PORT_RANGE_PARAM));
 
-        SupportedClassifierDefinition supportedClassifierDefinition = new SupportedClassifierDefinitionBuilder()
-            .setClassifierDefinitionId(L4ClassifierDefinition.ID)
-            .setSupportedParameterValues(
-                    ImmutableList.<SupportedParameterValues>of(new SupportedParameterValuesBuilder()
-                        .setParameterName(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM)).build()))
-            .build();
-        Renderer renderer = createRenderer("renderer1");
-        registerSupportedClassifierDefByRenderer(supportedClassifierDefinition, renderer);
-
-        ClassifierDefinition newCd = listener.createClassifierDefinitionWithUnionOfParams(L4ClassifierDefinition.ID,
-                getDataBroker().newReadOnlyTransaction());
+        listener.putOrRemoveClassifierDefinitionInOperDs(L4ClassifierDefinition.ID, supportedParams);
+        Optional<ClassifierDefinition> potentialCd = getDataBroker().newReadOnlyTransaction()
+            .read(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(L4ClassifierDefinition.ID))
+            .get();
         ClassifierDefinition expectedCd = new ClassifierDefinitionBuilder(L4ClassifierDefinition.DEFINITION)
-            .setParameter(ImmutableList.<Parameter>of(getParameterFromDefinition(L4ClassifierDefinition.DEFINITION,
-                    L4ClassifierDefinition.DST_PORT_PARAM)))
+            .setParameter(ImmutableList.<Parameter>of(
+                    getParameterFromDefinition(L4ClassifierDefinition.DEFINITION,
+                            L4ClassifierDefinition.DST_PORT_PARAM),
+                    getParameterFromDefinition(L4ClassifierDefinition.DEFINITION,
+                            L4ClassifierDefinition.DST_PORT_RANGE_PARAM)))
             .build();
-        Assert.assertEquals(expectedCd, newCd);
+        Assert.assertTrue(potentialCd.isPresent());
+        assertEquals(expectedCd, potentialCd.get());
     }
 
-    private Renderer createRenderer(String rendererName) {
-        return new RendererBuilder().setName(new RendererName(rendererName)).build();
+    private void assertEquals(ClassifierDefinition expectedCd, ClassifierDefinition actualCd) {
+        Assert.assertEquals(expectedCd.getId(), actualCd.getId());
+        Assert.assertEquals(expectedCd.getName(), actualCd.getName());
+        Assert.assertEquals(expectedCd.getDescription(), actualCd.getDescription());
+        Assert.assertEquals(expectedCd.getFallbackBehavior(), actualCd.getFallbackBehavior());
+        List<Parameter> expectedParams = getNonNullList(expectedCd.getParameter());
+        List<Parameter> actualParams = getNonNullList(actualCd.getParameter());
+        Assert.assertTrue(expectedParams.containsAll(actualParams) && actualParams.containsAll(expectedParams));
     }
 
+    private <T> List<T> getNonNullList(List<T> list) {
+        return MoreObjects.firstNonNull(list, ImmutableList.<T>of());
+    }
+
+    // @Test
+    // public void testCreateClassifierDefinitionWithUnionOfParams_allParamsSupportedByRenderer()
+    // throws Exception {
+    // WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
+    // wTx.put(LogicalDatastoreType.CONFIGURATION,
+    // IidFactory.classifierDefinitionIid(EtherTypeClassifierDefinition.ID),
+    // EtherTypeClassifierDefinition.DEFINITION, true);
+    // wTx.submit().get();
+    //
+    // SupportedClassifierDefinition supportedClassifierDefinition = new
+    // SupportedClassifierDefinitionBuilder()
+    // .setClassifierDefinitionId(EtherTypeClassifierDefinition.ID)
+    // .setSupportedParameterValues(
+    // ImmutableList.<SupportedParameterValues>of(new SupportedParameterValuesBuilder()
+    // .setParameterName(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)).build()))
+    // .build();
+    // Renderer renderer = createRenderer("renderer1");
+    // registerSupportedClassifierDefByRenderer(supportedClassifierDefinition, renderer);
+    //
+    // ClassifierDefinition newCd = listener.createClassifierDefinitionWithUnionOfParams(
+    // EtherTypeClassifierDefinition.ID, getDataBroker().newReadOnlyTransaction());
+    // Assert.assertEquals(EtherTypeClassifierDefinition.DEFINITION, newCd);
+    // }
+
+    // @Test
+    // public void testCreateClassifierDefinitionWithUnionOfParams_someParamsSupportedByRenderer()
+    // throws Exception {
+    // WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
+    // wTx.put(LogicalDatastoreType.CONFIGURATION,
+    // IidFactory.classifierDefinitionIid(L4ClassifierDefinition.ID),
+    // L4ClassifierDefinition.DEFINITION, true);
+    // wTx.submit().get();
+    //
+    // SupportedClassifierDefinition supportedClassifierDefinition = new
+    // SupportedClassifierDefinitionBuilder()
+    // .setClassifierDefinitionId(L4ClassifierDefinition.ID)
+    // .setSupportedParameterValues(
+    // ImmutableList.<SupportedParameterValues>of(new SupportedParameterValuesBuilder()
+    // .setParameterName(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM)).build()))
+    // .build();
+    // Renderer renderer = createRenderer("renderer1");
+    // registerSupportedClassifierDefByRenderer(supportedClassifierDefinition, renderer);
+    //
+    // ClassifierDefinition newCd =
+    // listener.createClassifierDefinitionWithUnionOfParams(L4ClassifierDefinition.ID,
+    // getDataBroker().newReadOnlyTransaction());
+    // ClassifierDefinition expectedCd = new
+    // ClassifierDefinitionBuilder(L4ClassifierDefinition.DEFINITION)
+    // .setParameter(ImmutableList.<Parameter>of(getParameterFromDefinition(L4ClassifierDefinition.DEFINITION,
+    // L4ClassifierDefinition.DST_PORT_PARAM)))
+    // .build();
+    // Assert.assertEquals(expectedCd, newCd);
+    // }
+    //
+    // private Renderer createRenderer(String rendererName) {
+    // return new RendererBuilder().setName(new RendererName(rendererName)).build();
+    // }
+    //
     private Parameter getParameterFromDefinition(ClassifierDefinition cd, String parameter) {
         for (Parameter param : cd.getParameter()) {
             if (param.getName().getValue().equals(parameter)) {
@@ -94,17 +339,20 @@ public class SupportedClassifierDefinitionListenerTest extends GbpDataBrokerTest
         }
         throw new IllegalArgumentException("Parameter " + parameter + " is not located in " + cd);
     }
-
-    private void registerSupportedClassifierDefByRenderer(SupportedClassifierDefinition supportedClassifierDefinition,
-            Renderer renderer) {
-        InstanceIdentifier<SupportedClassifierDefinition> scdIid = InstanceIdentifier.builder(Renderers.class)
-            .child(Renderer.class, renderer.getKey())
-            .child(Capabilities.class)
-            .child(SupportedClassifierDefinition.class, supportedClassifierDefinition.getKey())
-            .build();
-        listener.ciValidatorBySupportedCdIid.put(scdIid,
-                new ClassifierInstanceValidator(supportedClassifierDefinition));
-        listener.supportedCdIidByCdId.put(supportedClassifierDefinition.getClassifierDefinitionId(), scdIid);
-    }
+    //
+    // private void registerSupportedClassifierDefByRenderer(SupportedClassifierDefinition
+    // supportedClassifierDefinition,
+    // Renderer renderer) {
+    // InstanceIdentifier<SupportedClassifierDefinition> scdIid =
+    // InstanceIdentifier.builder(Renderers.class)
+    // .child(Renderer.class, renderer.getKey())
+    // .child(Capabilities.class)
+    // .child(SupportedClassifierDefinition.class, supportedClassifierDefinition.getKey())
+    // .build();
+    // listener.ciValidatorBySupportedCdKey.put(new SupportedCdKey(scdIid, null),
+    // new ClassifierInstanceValidator(supportedClassifierDefinition));
+    // listener.supportedCdIidByCdId.put(supportedClassifierDefinition.getClassifierDefinitionId(),
+    // scdIid);
+    // }
 
 }