Bug 5510 - Modifying DataTreeChangeHandler
[groupbasedpolicy.git] / groupbasedpolicy / src / main / java / org / opendaylight / groupbasedpolicy / sf / SupportedClassifierDefinitionListener.java
1 /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.groupbasedpolicy.sf;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.Set;
15
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
19 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.groupbasedpolicy.api.PolicyValidatorRegistry;
22 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
23 import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
24 import org.opendaylight.groupbasedpolicy.util.IidFactory;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedClassifierDefinition;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.google.common.annotations.VisibleForTesting;
38 import com.google.common.base.Function;
39 import com.google.common.base.Optional;
40 import com.google.common.base.Predicate;
41 import com.google.common.collect.Collections2;
42 import com.google.common.collect.FluentIterable;
43 import com.google.common.collect.HashBasedTable;
44 import com.google.common.collect.Table;
45
46 public class SupportedClassifierDefinitionListener extends DataTreeChangeHandler<SupportedClassifierDefinition> {
47
48     private static final Logger LOG = LoggerFactory.getLogger(SupportedClassifierDefinitionListener.class);
49
50     @VisibleForTesting
51     final Table<RendererName, ClassifierDefinitionId, ClassifierInstanceValidator> validatorByRendererAndCd =
52             HashBasedTable.create();
53     private final PolicyValidatorRegistry validatorRegistry;
54
55     public SupportedClassifierDefinitionListener(DataBroker dataProvider, PolicyValidatorRegistry validatorRegistry) {
56         super(dataProvider);
57         this.validatorRegistry = validatorRegistry;
58         if (validatorRegistry == null) {
59             LOG.info(
60                     "{} service was NOT found. Automatic registration of simple classifier-instance validators is NOT available for renderers.",
61                     PolicyValidatorRegistry.class.getCanonicalName());
62         } else {
63             LOG.info(
64                     "{} service was found. Automatic registration of simple classifier-instance validators is available for renderers.",
65                     PolicyValidatorRegistry.class.getCanonicalName());
66         }
67         registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
68                 IidFactory.supportedClassifierDefinitionIidWildcard()));
69     }
70
71     @Override
72     protected void onWrite(DataObjectModification<SupportedClassifierDefinition> rootNode,
73             InstanceIdentifier<SupportedClassifierDefinition> createdSupportedCdIid) {
74         SupportedClassifierDefinition createdSupportedCd = rootNode.getDataAfter();
75         RendererName rendererName = createdSupportedCdIid.firstKeyOf(Renderer.class).getName();
76         ClassifierInstanceValidator ciValidator = new ClassifierInstanceValidator(createdSupportedCd, rendererName);
77         setParentValidators(ciValidator, false);
78         ClassifierDefinitionId cdId = createdSupportedCd.getClassifierDefinitionId();
79         validatorByRendererAndCd.put(rendererName, cdId, ciValidator);
80         if (validatorRegistry != null) {
81             validatorRegistry.register(cdId, ciValidator);
82         }
83         putOrRemoveClassifierDefinitionInOperDs(cdId, getAllSupportedParams(cdId));
84     }
85
86     @Override
87     protected void onDelete(DataObjectModification<SupportedClassifierDefinition> rootNode,
88             InstanceIdentifier<SupportedClassifierDefinition> removedSupportedCdIid) {
89         SupportedClassifierDefinition removedSupportedCd = rootNode.getDataBefore();
90         ClassifierDefinitionId cdId = removedSupportedCd.getClassifierDefinitionId();
91         RendererName rendererName = removedSupportedCdIid.firstKeyOf(Renderer.class).getName();
92         ClassifierInstanceValidator removedCiValidator = validatorByRendererAndCd.remove(rendererName, cdId);
93         if (validatorRegistry != null) {
94             validatorRegistry.unregister(cdId, removedCiValidator);
95         }
96         setParentValidators(removedCiValidator, true);
97         putOrRemoveClassifierDefinitionInOperDs(cdId, getAllSupportedParams(cdId));
98     }
99
100     @Override
101     protected void onSubtreeModified(DataObjectModification<SupportedClassifierDefinition> rootNode,
102             InstanceIdentifier<SupportedClassifierDefinition> modifiedSupportedCdIid) {
103         SupportedClassifierDefinition beforeSupportedCd = rootNode.getDataBefore();
104         ClassifierDefinitionId cdId = beforeSupportedCd.getClassifierDefinitionId();
105         RendererName rendererName = modifiedSupportedCdIid.firstKeyOf(Renderer.class).getName();
106         ClassifierInstanceValidator oldCiValidator = validatorByRendererAndCd.remove(rendererName, cdId);
107         if (validatorRegistry != null) {
108             validatorRegistry.unregister(cdId, oldCiValidator);
109         }
110         SupportedClassifierDefinition afterSupportedCd = rootNode.getDataAfter();
111         ClassifierInstanceValidator newCiValidator = new ClassifierInstanceValidator(afterSupportedCd, rendererName);
112         setParentValidators(newCiValidator, false);
113         validatorByRendererAndCd.put(rendererName, cdId, newCiValidator);
114         if (validatorRegistry != null) {
115             validatorRegistry.register(cdId, newCiValidator);
116         }
117         putOrRemoveClassifierDefinitionInOperDs(cdId, getAllSupportedParams(cdId));
118     }
119
120     @VisibleForTesting
121     void setParentValidators(ClassifierInstanceValidator ciValidator, boolean setParentToNull) {
122         if (ciValidator.getParentClassifierDefinitionId() != null && !setParentToNull) {
123             ClassifierInstanceValidator parentCiValidator = validatorByRendererAndCd.get(ciValidator.getRendererName(),
124                     ciValidator.getParentClassifierDefinitionId());
125             if (parentCiValidator != null) {
126                 ciValidator.setParentValidator(parentCiValidator);
127             }
128         }
129         for (ClassifierInstanceValidator existingCiValidator : getValidatorsWithParentCdForRenderer(
130                 ciValidator.getClassifierDefinitionId(), ciValidator.getRendererName())) {
131             if (setParentToNull) {
132                 existingCiValidator.setParentValidator(null);
133             } else {
134                 existingCiValidator.setParentValidator(ciValidator);
135             }
136         }
137     }
138
139     @VisibleForTesting
140     Collection<ClassifierInstanceValidator> getValidatorsWithParentCdForRenderer(
141             final ClassifierDefinitionId parentCdId, RendererName renderer) {
142         return Collections2.filter(validatorByRendererAndCd.row(renderer).values(),
143                 new Predicate<ClassifierInstanceValidator>() {
144
145                     @Override
146                     public boolean apply(ClassifierInstanceValidator ciValidator) {
147                         if (parentCdId.equals(ciValidator.getParentClassifierDefinitionId())) {
148                             return true;
149                         }
150                         return false;
151                     }
152                 });
153     }
154
155     @VisibleForTesting
156     List<ParameterName> getAllSupportedParams(final ClassifierDefinitionId cdId) {
157         return FluentIterable.from(validatorByRendererAndCd.column(cdId).values())
158             .transformAndConcat(new Function<ClassifierInstanceValidator, Set<ParameterName>>() {
159
160                 @Override
161                 public Set<ParameterName> apply(ClassifierInstanceValidator input) {
162                     return input.getSupportedParameters();
163                 }
164             })
165             .toList();
166     }
167
168     @VisibleForTesting
169     void putOrRemoveClassifierDefinitionInOperDs(ClassifierDefinitionId cdId, List<ParameterName> supportedParams) {
170         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
171         Optional<ClassifierDefinition> potentialCdFromConfDs = DataStoreHelper
172             .readFromDs(LogicalDatastoreType.CONFIGURATION, IidFactory.classifierDefinitionIid(cdId), rwTx);
173         if (!potentialCdFromConfDs.isPresent()) {
174             LOG.error("Classifier-definition with ID {} does not exist in CONF datastore.", cdId);
175             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(cdId),
176                     rwTx);
177             DataStoreHelper.submitToDs(rwTx);
178             return;
179         }
180         ClassifierDefinition cd =
181                 createClassifierDefinitionWithUnionOfParams(potentialCdFromConfDs.get(), supportedParams);
182         if (cd != null) {
183             rwTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(cdId), cd);
184         } else {
185             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, IidFactory.classifierDefinitionIid(cdId),
186                     rwTx);
187         }
188         DataStoreHelper.submitToDs(rwTx);
189     }
190
191     @VisibleForTesting
192     static ClassifierDefinition createClassifierDefinitionWithUnionOfParams(ClassifierDefinition cd,
193             List<ParameterName> supportedParams) {
194         if (supportedParams == null || supportedParams.isEmpty()) {
195             LOG.debug("Classifier-definition with ID {} is not supported by any renderer.", cd.getId().getValue());
196             return null;
197         }
198         if (cd.getParameter() == null || cd.getParameter().isEmpty()) {
199             LOG.trace("Classifier-definition with ID {} does not contain any parameter in CONF datastore.",
200                     cd.getId().getValue());
201             return cd;
202         }
203         List<Parameter> params = new ArrayList<>();
204         for (ParameterName supportedParam : supportedParams) {
205             for (Parameter param : cd.getParameter()) {
206                 if (param.getName().equals(supportedParam)) {
207                     params.add(param);
208                 }
209             }
210         }
211         ClassifierDefinitionBuilder cdBuilder = new ClassifierDefinitionBuilder(cd);
212         return cdBuilder.setParameter(params).build();
213     }
214
215 }