2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.elan.l2gw.ha.merge;
10 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
11 import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
13 import java.util.Collection;
14 import java.util.HashMap;
16 import java.util.Objects;
17 import java.util.Optional;
18 import java.util.concurrent.ExecutionException;
19 import java.util.function.BiPredicate;
20 import org.opendaylight.genius.utils.SuperTypeUtil;
21 import org.opendaylight.mdsal.binding.api.DataObjectModification;
22 import org.opendaylight.mdsal.binding.util.Datastore;
23 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
24 import org.opendaylight.mdsal.binding.util.Datastore.Operational;
25 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
26 import org.opendaylight.netvirt.elan.l2gw.ha.commands.LocalMcastCmd;
27 import org.opendaylight.netvirt.elan.l2gw.ha.commands.LocalUcastCmd;
28 import org.opendaylight.netvirt.elan.l2gw.ha.commands.MergeCommand;
29 import org.opendaylight.netvirt.elan.l2gw.ha.commands.PhysicalLocatorCmd;
30 import org.opendaylight.netvirt.elan.l2gw.ha.commands.RemoteMcastCmd;
31 import org.opendaylight.netvirt.elan.l2gw.ha.commands.RemoteUcastCmd;
32 import org.opendaylight.netvirt.elan.l2gw.ha.commands.TerminationPointCmd;
33 import org.opendaylight.netvirt.elan.l2gw.ha.commands.TunnelCmd;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalMcastMacs;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
41 import org.opendaylight.yangtools.concepts.Builder;
42 import org.opendaylight.yangtools.yang.binding.DataObject;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 public abstract class MergeCommandsAggregator<BuilderTypeT extends Builder, AugTypeT extends DataObject> {
49 private static final Logger LOG = LoggerFactory.getLogger(MergeCommandsAggregator.class);
51 protected Map<Class<?>, MergeCommand> commands = new HashMap<>();
53 private final Map<Class, Boolean> operSkipCommands = new HashMap<>();
54 private final Map<Class, Boolean> configSkipCommands = new HashMap<>();
56 private final BiPredicate<Class<? extends Datastore>, Class> skipCopy =
57 (dsType, cmdType) -> (Configuration.class.equals(dsType) ? configSkipCommands.containsKey(cmdType)
58 : operSkipCommands.containsKey(cmdType));
60 protected MergeCommandsAggregator() {
61 operSkipCommands.put(RemoteUcastCmd.class, Boolean.TRUE);
62 operSkipCommands.put(RemoteMcastCmd.class, Boolean.TRUE);
63 operSkipCommands.put(TerminationPointCmd.class, Boolean.TRUE);
64 operSkipCommands.put(LocalMcastCmd.class, Boolean.TRUE);
65 operSkipCommands.put(PhysicalLocatorCmd.class, Boolean.TRUE);
66 operSkipCommands.put(TunnelCmd.class, Boolean.TRUE);
68 operSkipCommands.put(RemoteMcastMacs.class, Boolean.TRUE);
69 operSkipCommands.put(RemoteUcastMacs.class, Boolean.TRUE);
70 operSkipCommands.put(LocalMcastMacs.class, Boolean.TRUE);
71 operSkipCommands.put(TerminationPoint.class, Boolean.TRUE);
72 operSkipCommands.put(Tunnels.class, Boolean.TRUE);
74 configSkipCommands.put(LocalUcastCmd.class, Boolean.TRUE);
75 configSkipCommands.put(LocalUcastMacs.class, Boolean.TRUE);
78 protected void addCommand(MergeCommand mergeCommand) {
79 commands.put(SuperTypeUtil.getTypeParameter(mergeCommand.getClass(), 0), mergeCommand);
82 public void mergeOperationalData(BuilderTypeT builder,
83 AugTypeT existingData,
85 InstanceIdentifier<Node> dstPath) {
86 for (MergeCommand cmd : commands.values()) {
87 if (skipCopy.negate().test(OPERATIONAL, cmd.getClass())) {
88 cmd.mergeOperationalData(builder, existingData, src, dstPath);
93 public void mergeConfigData(BuilderTypeT builder,
95 InstanceIdentifier<Node> dstPath) {
96 for (MergeCommand cmd : commands.values()) {
97 if (skipCopy.negate().test(CONFIGURATION, cmd.getClass())) {
98 cmd.mergeConfigData(builder, src, dstPath);
104 public void mergeConfigUpdate(InstanceIdentifier<Node> dstPath,
105 DataObjectModification mod,
106 TypedReadWriteTransaction<Configuration> tx) {
107 mergeUpdate(dstPath, mod, CONFIGURATION, tx);
110 public void mergeOpUpdate(InstanceIdentifier<Node> dstPath,
111 DataObjectModification mod,
112 TypedReadWriteTransaction<Operational> tx) {
113 mergeUpdate(dstPath, mod, OPERATIONAL, tx);
116 public <D extends Datastore> void mergeUpdate(InstanceIdentifier<Node> dstPath,
117 DataObjectModification mod,
118 Class<D> datastoreType,
119 TypedReadWriteTransaction<D> tx) {
123 Collection<DataObjectModification> modifications = mod.getModifiedChildren();
124 modifications.stream()
125 .filter(modification -> skipCopy.negate().test(datastoreType, modification.getDataType()))
126 .filter(modification -> commands.get(modification.getDataType()) != null)
127 .peek(modification -> LOG.debug("Received {} modification {} copy/delete to {}",
128 datastoreType, modification, dstPath))
129 .forEach(modification -> {
130 MergeCommand mergeCommand = commands.get(modification.getDataType());
131 DataObject dataAfter = modification.getDataAfter();
132 boolean create = dataAfter != null;
133 DataObject data = create ? dataAfter : modification.getDataBefore();
134 InstanceIdentifier<DataObject> transformedId = mergeCommand.generateId(dstPath, data);
135 DataObject transformedItem = mergeCommand.transform(dstPath, data);
137 Optional<DataObject> existingDataOptional = null;
139 existingDataOptional = tx.read(transformedId).get();
140 } catch (InterruptedException | ExecutionException ex) {
141 LOG.error("Failed to read data {} from {}", transformedId, datastoreType);
145 String destination = Configuration.class.equals(datastoreType) ? "child" : "parent";
147 if (isDataUpdated(existingDataOptional, transformedItem)) {
148 LOG.debug("Copy to {} {} {}", destination, datastoreType, transformedId);
149 tx.mergeParentStructurePut(transformedId, transformedItem);
151 LOG.debug("Data not updated skip copy to {}", transformedId);
154 if (existingDataOptional.isPresent()) {
155 LOG.debug("Delete from {} {} {}", destination, datastoreType, transformedId);
156 tx.delete(transformedId);
158 LOG.debug("Delete skipped for {}", transformedId);
164 boolean isDataUpdated(Optional<DataObject> existingDataOptional, DataObject newData) {
165 return !existingDataOptional.isPresent() || !Objects.equals(existingDataOptional.get(), newData);