ebd98f8c1f551c23c60da6ae0f6b25ab5ce1b465
[controller.git] / opendaylight / config / config-manager-facade-xml / src / main / java / org / opendaylight / controller / config / facade / xml / strategy / MergeEditConfigStrategy.java
1 /*
2  * Copyright (c) 2015, 2017 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.config.facade.xml.strategy;
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.facade.xml.exception.ConfigHandlingException;
20 import org.opendaylight.controller.config.facade.xml.mapping.attributes.fromxml.AttributeConfigElement;
21 import org.opendaylight.controller.config.facade.xml.mapping.config.ServiceRegistryWrapper;
22 import org.opendaylight.controller.config.util.ConfigTransactionClient;
23 import org.opendaylight.controller.config.util.xml.DocumentedException;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
28
29     private static final Logger LOG = LoggerFactory.getLogger(MergeEditConfigStrategy.class);
30
31     public MergeEditConfigStrategy() {
32     }
33
34     @Override
35     void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
36             String module, String instance, ServiceRegistryWrapper services) throws ConfigHandlingException {
37         throw new ConfigHandlingException(String.format(
38                 "Unable to handle missing instance, no missing instances should "
39                 + "appear at this point, missing: %s : %s ",
40                 module, instance), DocumentedException.ErrorType.APPLICATION,
41                 DocumentedException.ErrorTag.OPERATION_FAILED, DocumentedException.ErrorSeverity.ERROR);
42     }
43
44     @Override
45     @SuppressWarnings("IllegalCatch")
46     void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on,
47             ServiceRegistryWrapper services) throws ConfigHandlingException {
48
49         for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
50             try {
51                 AttributeConfigElement ace = configAttributeEntry.getValue();
52
53                 if (!ace.getResolvedValue().isPresent()) {
54                     LOG.debug("Skipping attribute {} for {}", configAttributeEntry.getKey(), on);
55                     continue;
56                 }
57
58                 Object toBeMergedIn = ace.getResolvedValue().get();
59                 // Get the existing values so we can merge the new values with them.
60                 Attribute currentAttribute = ta.getAttribute(on, ace.getJmxName());
61                 Object oldValue = currentAttribute != null ? currentAttribute.getValue() : null;
62                 // Merge value with currentValue
63                 toBeMergedIn = merge(oldValue, toBeMergedIn);
64                 ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), toBeMergedIn));
65                 LOG.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), toBeMergedIn, on);
66             } catch (RuntimeException e) {
67                 LOG.error("Error while merging object names of {}", on, e);
68                 throw new ConfigHandlingException(String.format("Unable to set attributes for %s, "
69                                 + "Error with attribute %s : %s ",
70                         on,
71                         configAttributeEntry.getKey(),
72                         configAttributeEntry.getValue()),
73                         DocumentedException.ErrorType.APPLICATION,
74                         DocumentedException.ErrorTag.OPERATION_FAILED,
75                         DocumentedException.ErrorSeverity.ERROR);
76             }
77         }
78     }
79
80     /**
81      * Merge value into current value Currently, this is only implemented for arrays
82      * of ObjectNames, but that is the most common case for which it is needed.
83      */
84     protected Object merge(Object oldValue, Object toBeMergedIn) {
85         if (oldValue instanceof ObjectName[] && toBeMergedIn instanceof ObjectName[]) {
86             toBeMergedIn = mergeObjectNameArrays((ObjectName[]) oldValue, (ObjectName[]) toBeMergedIn);
87         }
88         return toBeMergedIn;
89     }
90
91     /**
92      * Merge value into current values This implements for arrays of ObjectNames,
93      * but that is the most common case for which it is needed.
94      *
95      * @param oldValue
96      *            - the new values to be merged into existing values
97      * @param toBeMergedIn
98      *            - the existing values
99      *
100      * @return an ObjectName[] consisting the elements of currentValue with an
101      *         elements from values not already present in currentValue added
102      *
103      */
104     protected ObjectName[] mergeObjectNameArrays(ObjectName[] oldValue, ObjectName[] toBeMergedIn) {
105         List<ObjectName> newValueList = new ArrayList<>();
106         newValueList.addAll(asList(oldValue));
107         /*
108          * It is guaranteed that old values do not contain transaction name. Since
109          * toBeMergedIn is filled using service references translated by
110          * ServiceRegistryWrapper, it is also guaranteed that this list will not contain
111          * transaction names. Run through the list of values to be merged. If we don't
112          * have them already, add them to the list.
113          */
114         for (ObjectName objName : toBeMergedIn) {
115             if (!newValueList.contains(objName)) {
116                 newValueList.add(objName);
117             }
118         }
119         return newValueList.toArray(new ObjectName[newValueList.size()]);
120     }
121 }