6f5356c7da20fde63fb09a0c69a6599e61832a71
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / ha / merge / MergeCommandsAggregator.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.elan.l2gw.ha.merge;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.Map;
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.infra.Datastore;
21 import org.opendaylight.genius.infra.Datastore.Configuration;
22 import org.opendaylight.genius.infra.Datastore.Operational;
23 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
24 import org.opendaylight.genius.utils.SuperTypeUtil;
25 import org.opendaylight.mdsal.binding.api.DataObjectModification;
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;
46
47 public abstract class MergeCommandsAggregator<BuilderTypeT extends Builder, AugTypeT extends DataObject> {
48
49     private static final Logger LOG = LoggerFactory.getLogger(MergeCommandsAggregator.class);
50
51     protected Map<Class<?>, MergeCommand> commands = new HashMap<>();
52
53     private final Map<Class, Boolean> operSkipCommands = new HashMap<>();
54     private final Map<Class, Boolean> configSkipCommands = new HashMap<>();
55
56     private final BiPredicate<Class<? extends Datastore>, Class> skipCopy =
57         (dsType, cmdType) -> (Configuration.class.equals(dsType) ? configSkipCommands.containsKey(cmdType)
58                 : operSkipCommands.containsKey(cmdType));
59
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);
67
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);
73
74         configSkipCommands.put(LocalUcastCmd.class, Boolean.TRUE);
75         configSkipCommands.put(LocalUcastMacs.class, Boolean.TRUE);
76     }
77
78     protected void addCommand(MergeCommand mergeCommand) {
79         commands.put(SuperTypeUtil.getTypeParameter(mergeCommand.getClass(), 0), mergeCommand);
80     }
81
82     public void mergeOperationalData(BuilderTypeT builder,
83                                      AugTypeT existingData,
84                                      AugTypeT src,
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);
89             }
90         }
91     }
92
93     public void mergeConfigData(BuilderTypeT builder,
94                                 AugTypeT src,
95                                 InstanceIdentifier<Node> dstPath) {
96         for (MergeCommand cmd : commands.values()) {
97             if (skipCopy.negate().test(CONFIGURATION, cmd.getClass())) {
98                 cmd.mergeConfigData(builder, src, dstPath);
99             }
100         }
101     }
102
103
104     public void mergeConfigUpdate(InstanceIdentifier<Node> dstPath,
105                                   DataObjectModification mod,
106                                   TypedReadWriteTransaction<Configuration> tx) {
107         mergeUpdate(dstPath, mod, CONFIGURATION, tx);
108     }
109
110     public void mergeOpUpdate(InstanceIdentifier<Node> dstPath,
111                               DataObjectModification mod,
112                               TypedReadWriteTransaction<Operational> tx) {
113         mergeUpdate(dstPath, mod, OPERATIONAL, tx);
114     }
115
116     public <D extends Datastore> void mergeUpdate(InstanceIdentifier<Node> dstPath,
117                             DataObjectModification mod,
118                             Class<D> datastoreType,
119                             TypedReadWriteTransaction<D> tx) {
120         if (mod == null) {
121             return;
122         }
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);
136
137                 Optional<DataObject> existingDataOptional = null;
138                 try {
139                     existingDataOptional = tx.read(transformedId).get();
140                 } catch (InterruptedException | ExecutionException ex) {
141                     LOG.error("Failed to read data {} from {}", transformedId, datastoreType);
142                     return;
143                 }
144
145                 String destination = Configuration.class.equals(datastoreType) ? "child" : "parent";
146                 if (create) {
147                     if (isDataUpdated(existingDataOptional, transformedItem)) {
148                         LOG.debug("Copy to {} {} {}", destination, datastoreType, transformedId);
149                         tx.mergeParentStructurePut(transformedId, transformedItem);
150                     } else {
151                         LOG.debug("Data not updated skip copy to {}", transformedId);
152                     }
153                 } else {
154                     if (existingDataOptional.isPresent()) {
155                         LOG.debug("Delete from {} {} {}", destination, datastoreType, transformedId);
156                         tx.delete(transformedId);
157                     } else {
158                         LOG.debug("Delete skipped for {}", transformedId);
159                     }
160                 }
161             });
162     }
163
164     boolean isDataUpdated(Optional<DataObject> existingDataOptional, DataObject newData) {
165         return !existingDataOptional.isPresent() || !Objects.equals(existingDataOptional.get(), newData);
166     }
167 }