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.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
12 import static org.opendaylight.mdsal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
14 import java.util.Collection;
15 import java.util.HashMap;
17 import java.util.Objects;
18 import java.util.Optional;
19 import java.util.concurrent.ExecutionException;
20 import java.util.function.BiPredicate;
21 import org.opendaylight.genius.infra.Datastore;
22 import org.opendaylight.genius.infra.Datastore.Configuration;
23 import org.opendaylight.genius.infra.Datastore.Operational;
24 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
25 import org.opendaylight.genius.utils.SuperTypeUtil;
26 import org.opendaylight.mdsal.binding.api.DataObjectModification;
27 import org.opendaylight.netvirt.elan.l2gw.ha.commands.LocalMcastCmd;
28 import org.opendaylight.netvirt.elan.l2gw.ha.commands.LocalUcastCmd;
29 import org.opendaylight.netvirt.elan.l2gw.ha.commands.MergeCommand;
30 import org.opendaylight.netvirt.elan.l2gw.ha.commands.PhysicalLocatorCmd;
31 import org.opendaylight.netvirt.elan.l2gw.ha.commands.RemoteMcastCmd;
32 import org.opendaylight.netvirt.elan.l2gw.ha.commands.RemoteUcastCmd;
33 import org.opendaylight.netvirt.elan.l2gw.ha.commands.TerminationPointCmd;
34 import org.opendaylight.netvirt.elan.l2gw.ha.commands.TunnelCmd;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalMcastMacs;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
42 import org.opendaylight.yangtools.concepts.Builder;
43 import org.opendaylight.yangtools.yang.binding.DataObject;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
48 public abstract class MergeCommandsAggregator<BuilderTypeT extends Builder, AugTypeT extends DataObject> {
50 private static final Logger LOG = LoggerFactory.getLogger(MergeCommandsAggregator.class);
52 protected Map<Class<?>, MergeCommand> commands = new HashMap<>();
54 private final Map<Class, Boolean> operSkipCommands = new HashMap<>();
55 private final Map<Class, Boolean> configSkipCommands = new HashMap<>();
57 private final BiPredicate<Class<? extends Datastore>, Class> skipCopy =
58 (dsType, cmdType) -> (Configuration.class.equals(dsType) ? configSkipCommands.containsKey(cmdType)
59 : operSkipCommands.containsKey(cmdType));
61 protected MergeCommandsAggregator() {
62 operSkipCommands.put(RemoteUcastCmd.class, Boolean.TRUE);
63 operSkipCommands.put(RemoteMcastCmd.class, Boolean.TRUE);
64 operSkipCommands.put(TerminationPointCmd.class, Boolean.TRUE);
65 operSkipCommands.put(LocalMcastCmd.class, Boolean.TRUE);
66 operSkipCommands.put(PhysicalLocatorCmd.class, Boolean.TRUE);
67 operSkipCommands.put(TunnelCmd.class, Boolean.TRUE);
69 operSkipCommands.put(RemoteMcastMacs.class, Boolean.TRUE);
70 operSkipCommands.put(RemoteUcastMacs.class, Boolean.TRUE);
71 operSkipCommands.put(LocalMcastMacs.class, Boolean.TRUE);
72 operSkipCommands.put(TerminationPoint.class, Boolean.TRUE);
73 operSkipCommands.put(Tunnels.class, Boolean.TRUE);
75 configSkipCommands.put(LocalUcastCmd.class, Boolean.TRUE);
76 configSkipCommands.put(LocalUcastMacs.class, Boolean.TRUE);
79 protected void addCommand(MergeCommand mergeCommand) {
80 commands.put(SuperTypeUtil.getTypeParameter(mergeCommand.getClass(), 0), mergeCommand);
83 public void mergeOperationalData(BuilderTypeT builder,
84 AugTypeT existingData,
86 InstanceIdentifier<Node> dstPath) {
87 for (MergeCommand cmd : commands.values()) {
88 if (skipCopy.negate().test(OPERATIONAL, cmd.getClass())) {
89 cmd.mergeOperationalData(builder, existingData, src, dstPath);
94 public void mergeConfigData(BuilderTypeT builder,
96 InstanceIdentifier<Node> dstPath) {
97 for (MergeCommand cmd : commands.values()) {
98 if (skipCopy.negate().test(CONFIGURATION, cmd.getClass())) {
99 cmd.mergeConfigData(builder, src, dstPath);
105 public void mergeConfigUpdate(InstanceIdentifier<Node> dstPath,
106 DataObjectModification mod,
107 TypedReadWriteTransaction<Configuration> tx) {
108 mergeUpdate(dstPath, mod, CONFIGURATION, tx);
111 public void mergeOpUpdate(InstanceIdentifier<Node> dstPath,
112 DataObjectModification mod,
113 TypedReadWriteTransaction<Operational> tx) {
114 mergeUpdate(dstPath, mod, OPERATIONAL, tx);
117 public <D extends Datastore> void mergeUpdate(InstanceIdentifier<Node> dstPath,
118 DataObjectModification mod,
119 Class<D> datastoreType,
120 TypedReadWriteTransaction<D> tx) {
124 Collection<DataObjectModification> modifications = mod.getModifiedChildren();
125 modifications.stream()
126 .filter(modification -> skipCopy.negate().test(datastoreType, modification.getDataType()))
127 .filter(modification -> commands.get(modification.getDataType()) != null)
128 .peek(modification -> LOG.debug("Received {} modification {} copy/delete to {}",
129 datastoreType, modification, dstPath))
130 .forEach(modification -> {
131 MergeCommand mergeCommand = commands.get(modification.getDataType());
132 DataObject dataAfter = modification.getDataAfter();
133 boolean create = dataAfter != null;
134 DataObject data = create ? dataAfter : modification.getDataBefore();
135 InstanceIdentifier<DataObject> transformedId = mergeCommand.generateId(dstPath, data);
136 DataObject transformedItem = mergeCommand.transform(dstPath, data);
138 Optional<DataObject> existingDataOptional = null;
140 existingDataOptional = tx.read(transformedId).get();
141 } catch (InterruptedException | ExecutionException ex) {
142 LOG.error("Failed to read data {} from {}", transformedId, datastoreType);
146 String destination = Configuration.class.equals(datastoreType) ? "child" : "parent";
148 if (isDataUpdated(existingDataOptional, transformedItem)) {
149 LOG.debug("Copy to {} {} {}", destination, datastoreType, transformedId);
150 tx.put(transformedId, transformedItem, CREATE_MISSING_PARENTS);
152 LOG.debug("Data not updated skip copy to {}", transformedId);
155 if (existingDataOptional.isPresent()) {
156 LOG.debug("Delete from {} {} {}", destination, datastoreType, transformedId);
157 tx.delete(transformedId);
159 LOG.debug("Delete skipped for {}", transformedId);
165 boolean isDataUpdated(Optional<DataObject> existingDataOptional, DataObject newData) {
166 return !existingDataOptional.isPresent() || !Objects.equals(existingDataOptional.get(), newData);