Introducing simple merge strategy for config subsystem
[controller.git] / opendaylight / netconf / config-netconf-connector / src / main / java / org / opendaylight / controller / netconf / confignetconfconnector / operations / editconfig / MergeEditConfigStrategy.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
10
11 import static java.util.Arrays.asList;
12
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import javax.management.Attribute;
18 import javax.management.ObjectName;
19 import org.opendaylight.controller.config.util.ConfigTransactionClient;
20 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
21 import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
22 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
23 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
28
29     private static final Logger logger = LoggerFactory.getLogger(MergeEditConfigStrategy.class);
30
31     public MergeEditConfigStrategy() {
32
33     }
34
35     @Override
36     void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
37                                String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
38         throw new NetconfConfigHandlingException(
39                 String.format("Unable to handle missing instance, no missing instances should appear at this point, missing: %s : %s ",
40                         module,
41                         instance),
42                 NetconfDocumentedException.ErrorType.application,
43                 NetconfDocumentedException.ErrorTag.operation_failed,
44                 NetconfDocumentedException.ErrorSeverity.error);
45     }
46
47     @Override
48     void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
49
50         for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
51             try {
52                 AttributeConfigElement ace = configAttributeEntry.getValue();
53
54                 if (!ace.getResolvedValue().isPresent()) {
55                     logger.debug("Skipping attribute {} for {}", configAttributeEntry.getKey(), on);
56                     continue;
57                 }
58
59                 Object toBeMergedIn = ace.getResolvedValue().get();
60                 // Get the existing values so we can merge the new values with them.
61                 Attribute currentAttribute = ta.getAttribute(on, ace.getJmxName());
62                 Object oldValue = (currentAttribute != null ? currentAttribute.getValue() : null);
63                 // Merge value with currentValue
64                 toBeMergedIn = merge(oldValue, toBeMergedIn);
65                 ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), toBeMergedIn));
66                 logger.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), toBeMergedIn, on);
67             } catch (Exception e) {
68                 logger.error("Error while merging objectnames of {}", on, e);
69                 throw new NetconfConfigHandlingException(String.format("Unable to set attributes for %s, Error with attribute %s : %s ",
70                         on,
71                         configAttributeEntry.getKey(),
72                         configAttributeEntry.getValue()),
73                         NetconfDocumentedException.ErrorType.application,
74                         NetconfDocumentedException.ErrorTag.operation_failed,
75                         NetconfDocumentedException.ErrorSeverity.error);
76             }
77         }
78     }
79
80     /**
81      * Merge value into current value
82      * Currently, this is only implemented for arrays of ObjectNames, but that is the
83      * most common case for which it is needed.
84      */
85     protected Object merge(Object oldValue, Object toBeMergedIn) {
86         if (oldValue instanceof ObjectName[] && toBeMergedIn instanceof ObjectName[]) {
87             toBeMergedIn = mergeObjectNameArrays((ObjectName[]) oldValue, (ObjectName[]) toBeMergedIn);
88         }
89         return toBeMergedIn;
90     }
91
92     /**
93      * Merge value into current values
94      * This implements for arrays of ObjectNames, but that is the
95      * most common case for which it is needed.
96      *
97      * @param oldValue - the new values to be merged into existing values
98      * @param toBeMergedIn - the existing values
99      *
100      * @return an ObjectName[] consisting the elements of currentValue with an elements from values not already present in currentValue added
101      *
102      */
103     protected ObjectName[] mergeObjectNameArrays(ObjectName[] oldValue, ObjectName[] toBeMergedIn) {
104         List<ObjectName> newValueList = new ArrayList<>();
105         newValueList.addAll(asList(oldValue));
106         /*
107          It is guaranteed that old values do not contain transaction name.
108          Since toBeMergedIn is filled using service references translated by ServiceRegistryWrapper, it
109          is also guaranteed that this list will not contain transaction names.
110          Run through the list of values to be merged.  If we don't have them already, add them to the list.
111          */
112         for (ObjectName objName : toBeMergedIn) {
113             if (!newValueList.contains(objName)) {
114                 newValueList.add(objName);
115             }
116         }
117         return newValueList.toArray(new ObjectName[newValueList.size()]);
118     }
119 }