NETVIRT-1630 migrate to md-sal APIs
[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 import static org.opendaylight.mdsal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
13
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.Map;
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;
47
48 public abstract class MergeCommandsAggregator<BuilderTypeT extends Builder, AugTypeT extends DataObject> {
49
50     private static final Logger LOG = LoggerFactory.getLogger(MergeCommandsAggregator.class);
51
52     protected Map<Class<?>, MergeCommand> commands = new HashMap<>();
53
54     private final Map<Class, Boolean> operSkipCommands = new HashMap<>();
55     private final Map<Class, Boolean> configSkipCommands = new HashMap<>();
56
57     private final BiPredicate<Class<? extends Datastore>, Class> skipCopy =
58         (dsType, cmdType) -> (Configuration.class.equals(dsType) ? configSkipCommands.containsKey(cmdType)
59                 : operSkipCommands.containsKey(cmdType));
60
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);
68
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);
74
75         configSkipCommands.put(LocalUcastCmd.class, Boolean.TRUE);
76         configSkipCommands.put(LocalUcastMacs.class, Boolean.TRUE);
77     }
78
79     protected void addCommand(MergeCommand mergeCommand) {
80         commands.put(SuperTypeUtil.getTypeParameter(mergeCommand.getClass(), 0), mergeCommand);
81     }
82
83     public void mergeOperationalData(BuilderTypeT builder,
84                                      AugTypeT existingData,
85                                      AugTypeT src,
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);
90             }
91         }
92     }
93
94     public void mergeConfigData(BuilderTypeT builder,
95                                 AugTypeT src,
96                                 InstanceIdentifier<Node> dstPath) {
97         for (MergeCommand cmd : commands.values()) {
98             if (skipCopy.negate().test(CONFIGURATION, cmd.getClass())) {
99                 cmd.mergeConfigData(builder, src, dstPath);
100             }
101         }
102     }
103
104
105     public void mergeConfigUpdate(InstanceIdentifier<Node> dstPath,
106                                   DataObjectModification mod,
107                                   TypedReadWriteTransaction<Configuration> tx) {
108         mergeUpdate(dstPath, mod, CONFIGURATION, tx);
109     }
110
111     public void mergeOpUpdate(InstanceIdentifier<Node> dstPath,
112                               DataObjectModification mod,
113                               TypedReadWriteTransaction<Operational> tx) {
114         mergeUpdate(dstPath, mod, OPERATIONAL, tx);
115     }
116
117     public <D extends Datastore> void mergeUpdate(InstanceIdentifier<Node> dstPath,
118                             DataObjectModification mod,
119                             Class<D> datastoreType,
120                             TypedReadWriteTransaction<D> tx) {
121         if (mod == null) {
122             return;
123         }
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);
137
138                 Optional<DataObject> existingDataOptional = null;
139                 try {
140                     existingDataOptional = tx.read(transformedId).get();
141                 } catch (InterruptedException | ExecutionException ex) {
142                     LOG.error("Failed to read data {} from {}", transformedId, datastoreType);
143                     return;
144                 }
145
146                 String destination = Configuration.class.equals(datastoreType) ? "child" : "parent";
147                 if (create) {
148                     if (isDataUpdated(existingDataOptional, transformedItem)) {
149                         LOG.debug("Copy to {} {} {}", destination, datastoreType, transformedId);
150                         tx.put(transformedId, transformedItem, CREATE_MISSING_PARENTS);
151                     } else {
152                         LOG.debug("Data not updated skip copy to {}", transformedId);
153                     }
154                 } else {
155                     if (existingDataOptional.isPresent()) {
156                         LOG.debug("Delete from {} {} {}", destination, datastoreType, transformedId);
157                         tx.delete(transformedId);
158                     } else {
159                         LOG.debug("Delete skipped for {}", transformedId);
160                     }
161                 }
162             });
163     }
164
165     boolean isDataUpdated(Optional<DataObject> existingDataOptional, DataObject newData) {
166         return !existingDataOptional.isPresent() || !Objects.equals(existingDataOptional.get(), newData);
167     }
168 }