/* * Copyright (c) 2015, 2017 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.controller.config.facade.xml.strategy; import static java.util.Arrays.asList; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.management.Attribute; import javax.management.ObjectName; import org.opendaylight.controller.config.facade.xml.exception.ConfigHandlingException; import org.opendaylight.controller.config.facade.xml.mapping.attributes.fromxml.AttributeConfigElement; import org.opendaylight.controller.config.facade.xml.mapping.config.ServiceRegistryWrapper; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.util.xml.DocumentedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MergeEditConfigStrategy extends AbstractEditConfigStrategy { private static final Logger LOG = LoggerFactory.getLogger(MergeEditConfigStrategy.class); public MergeEditConfigStrategy() { } @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, String module, String instance, ServiceRegistryWrapper services) throws ConfigHandlingException { throw new ConfigHandlingException(String.format( "Unable to handle missing instance, no missing instances should " + "appear at this point, missing: %s : %s ", module, instance), DocumentedException.ErrorType.APPLICATION, DocumentedException.ErrorTag.OPERATION_FAILED, DocumentedException.ErrorSeverity.ERROR); } @Override @SuppressWarnings("IllegalCatch") void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on, ServiceRegistryWrapper services) throws ConfigHandlingException { for (Entry configAttributeEntry : configuration.entrySet()) { try { AttributeConfigElement ace = configAttributeEntry.getValue(); if (!ace.getResolvedValue().isPresent()) { LOG.debug("Skipping attribute {} for {}", configAttributeEntry.getKey(), on); continue; } Object toBeMergedIn = ace.getResolvedValue().get(); // Get the existing values so we can merge the new values with them. Attribute currentAttribute = ta.getAttribute(on, ace.getJmxName()); Object oldValue = currentAttribute != null ? currentAttribute.getValue() : null; // Merge value with currentValue toBeMergedIn = merge(oldValue, toBeMergedIn); ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), toBeMergedIn)); LOG.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), toBeMergedIn, on); } catch (RuntimeException e) { LOG.error("Error while merging object names of {}", on, e); throw new ConfigHandlingException(String.format("Unable to set attributes for %s, " + "Error with attribute %s : %s ", on, configAttributeEntry.getKey(), configAttributeEntry.getValue()), e, DocumentedException.ErrorType.APPLICATION, DocumentedException.ErrorTag.OPERATION_FAILED, DocumentedException.ErrorSeverity.ERROR); } } } /** * Merge value into current value Currently, this is only implemented for arrays * of ObjectNames, but that is the most common case for which it is needed. */ protected Object merge(Object oldValue, Object toBeMergedIn) { if (oldValue instanceof ObjectName[] && toBeMergedIn instanceof ObjectName[]) { toBeMergedIn = mergeObjectNameArrays((ObjectName[]) oldValue, (ObjectName[]) toBeMergedIn); } return toBeMergedIn; } /** * Merge value into current values This implements for arrays of ObjectNames, * but that is the most common case for which it is needed. * * @param oldValue * - the new values to be merged into existing values * @param toBeMergedIn * - the existing values * * @return an ObjectName[] consisting the elements of currentValue with an * elements from values not already present in currentValue added * */ protected ObjectName[] mergeObjectNameArrays(ObjectName[] oldValue, ObjectName[] toBeMergedIn) { List newValueList = new ArrayList<>(); newValueList.addAll(asList(oldValue)); /* * It is guaranteed that old values do not contain transaction name. Since * toBeMergedIn is filled using service references translated by * ServiceRegistryWrapper, it is also guaranteed that this list will not contain * transaction names. Run through the list of values to be merged. If we don't * have them already, add them to the list. */ for (ObjectName objName : toBeMergedIn) { if (!newValueList.contains(objName)) { newValueList.add(objName); } } return newValueList.toArray(new ObjectName[newValueList.size()]); } }