Make methods static
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / TransactCommandAggregator.java
1 /*
2  * Copyright (c) 2015, 2017 China Telecom Beijing Research Institute 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.ovsdb.hwvtepsouthbound.transact;
9
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Objects;
16 import java.util.concurrent.atomic.AtomicInteger;
17 import org.apache.commons.lang3.tuple.Pair;
18 import org.opendaylight.mdsal.binding.api.DataObjectModification;
19 import org.opendaylight.mdsal.binding.api.DataTreeModification;
20 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
21 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.binding.Identifiable;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 public class TransactCommandAggregator implements TransactCommand {
33     private static final Logger LOG = LoggerFactory.getLogger(TransactCommandAggregator.class);
34
35     private final List<TransactCommand> commands = new ArrayList<>();
36     private final AtomicInteger retryCount = new AtomicInteger(HwvtepSouthboundConstants.CHAIN_RETRY_COUNT);
37     private final HwvtepOperationalState operationalState;
38     /* stores the modified and deleted data for each child type of each node id
39        Map<nodeid , Pair < updated, deleted >
40        each updated/ deleted contains Map < child type, List<ChildData>>
41        child type is the child of hwvtep Global augmentation
42      */
43     private final Map<InstanceIdentifier<Node>,
44             Pair<Map<Class<? extends Identifiable>, List<Identifiable>>,
45                 Map<Class<? extends Identifiable>, List<Identifiable>>>> modifiedData = new HashMap<>();
46
47
48     public TransactCommandAggregator(HwvtepOperationalState state, Collection<DataTreeModification<Node>> changes) {
49         this.operationalState = state;
50         onDataTreeChanged(changes);
51         commands.add(new PhysicalSwitchUpdateCommand(state,changes));
52         commands.add(new PhysicalSwitchRemoveCommand(state,changes));
53         commands.add(new LogicalSwitchUpdateCommand(state,changes));
54         commands.add(new LogicalSwitchRemoveCommand(state,changes));
55         commands.add(new PhysicalPortUpdateCommand(state,changes));
56         commands.add(new PhysicalPortRemoveCommand(state,changes));
57         commands.add(new McastMacsRemoteUpdateCommand(state,changes));
58         commands.add(new McastMacsRemoteRemoveCommand(state,changes));
59         commands.add(new McastMacsLocalUpdateCommand(state,changes));
60         commands.add(new McastMacsLocalRemoveCommand(state,changes));
61         commands.add(new UcastMacsRemoteUpdateCommand(state,changes));
62         commands.add(new UcastMacsRemoteRemoveCommand(state,changes));
63         commands.add(new UcastMacsLocalUpdateCommand(state,changes));
64         commands.add(new UcastMacsLocalRemoveCommand(state,changes));
65         commands.add(new TunnelUpdateCommand(state,changes));
66         commands.add(new TunnelRemoveCommand(state,changes));
67         commands.add(new LogicalRouterUpdateCommand(state,changes));
68         commands.add(new LogicalRouterRemoveCommand(state,changes));
69     }
70
71     @Override
72     public void execute(TransactionBuilder transaction) {
73         for (TransactCommand command:commands) {
74             try {
75                 command.execute(transaction);
76             } catch (NullPointerException e) {
77                 LOG.error("Execution of command {} failed with the following exception."
78                         + " Continuing the execution of remaining commands", command, e);
79             }
80         }
81     }
82
83     @Override
84     public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data,
85                                InstanceIdentifier key,
86                                Object... extraData) {
87     }
88
89     @Override
90     public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data,
91                                     InstanceIdentifier key,
92                                     Object... extraData) {
93     }
94
95     private void onDataTreeChanged(final Collection<DataTreeModification<Node>> changes) {
96         boolean readOperationalNodes = false;
97         for (DataTreeModification<Node> change : changes) {
98             final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
99             final DataObjectModification<Node> mod = change.getRootNode();
100             final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData = new HashMap<>();
101             final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData = new HashMap<>();
102             extractDataChanged(key, mod, updatedData, deletedData);
103             modifiedData.put(key, Pair.of(updatedData, deletedData));
104             operationalState.setModifiedData(modifiedData);
105             if (!isMacOnlyUpdate(updatedData, deletedData)) {
106                 readOperationalNodes = true;
107             }
108         }
109         if (readOperationalNodes) {
110             operationalState.readOperationalNodes();
111         }
112     }
113
114     private static boolean isMacOnlyUpdate(final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
115                                            final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
116         return updatedData.containsKey(RemoteUcastMacs.class) && updatedData.size() == 1
117                 || deletedData.containsKey(RemoteUcastMacs.class) && deletedData.size() == 1;
118     }
119
120     private static void extractDataChanged(final InstanceIdentifier<Node> key,
121                                            final DataObjectModification<Node> mod,
122                                            final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
123                                            final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
124
125         extractDataChanged(mod.getModifiedChildren(), updatedData, deletedData);
126         DataObjectModification<HwvtepGlobalAugmentation> aug = mod.getModifiedAugmentation(
127                 HwvtepGlobalAugmentation.class);
128         if (aug != null) {
129             extractDataChanged(aug.getModifiedChildren(), updatedData, deletedData);
130         }
131         DataObjectModification<PhysicalSwitchAugmentation> psAug = mod.getModifiedAugmentation(
132                 PhysicalSwitchAugmentation.class);
133         if (psAug != null) {
134             extractDataChanged(psAug.getModifiedChildren(), updatedData, deletedData);
135         }
136     }
137
138     private static void extractDataChanged(
139             final Collection<? extends DataObjectModification<? extends DataObject>> children,
140                     final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
141                     final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
142         if (children == null) {
143             return;
144         }
145         for (DataObjectModification<? extends DataObject> child : children) {
146             Class<? extends Identifiable> childClass = (Class<? extends Identifiable>) child.getDataType();
147             switch (child.getModificationType()) {
148                 case WRITE:
149                 case SUBTREE_MODIFIED:
150                     DataObject dataAfter = child.getDataAfter();
151                     if (!(dataAfter instanceof Identifiable)) {
152                         continue;
153                     }
154                     DataObject before = child.getDataBefore();
155                     if (Objects.equals(dataAfter, before)) {
156                         /*
157                         in cluster reboot scenarios,
158                         application rewrites the data tx.put( logicalswitchiid, logicalswitch )
159                         that time it fires the update again ignoring such updates here
160                          */
161                         continue;
162                     }
163                     Identifiable identifiable = (Identifiable) dataAfter;
164                     addToUpdatedData(updatedData, childClass, identifiable);
165                     break;
166                 case DELETE:
167                     DataObject dataBefore = child.getDataBefore();
168                     if (!(dataBefore instanceof Identifiable)) {
169                         continue;
170                     }
171                     addToUpdatedData(deletedData, childClass, (Identifiable)dataBefore);
172                     break;
173                 default:
174                     break;
175             }
176         }
177     }
178
179     private static void addToUpdatedData(Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
180                                          Class<? extends Identifiable> childClass, Identifiable identifiable) {
181         updatedData.computeIfAbsent(childClass, (cls) -> new ArrayList<>());
182         updatedData.get(childClass).add(identifiable);
183     }
184
185     @Override
186     public void onFailure(TransactionBuilder deviceTransaction) {
187         commands.forEach(cmd -> cmd.onFailure(deviceTransaction));
188         operationalState.clearIntransitKeys();
189     }
190
191     @Override
192     public void onSuccess(TransactionBuilder deviceTransaction) {
193         commands.forEach(cmd -> cmd.onSuccess(deviceTransaction));
194     }
195
196     @Override
197     public boolean retry() {
198         return retryCount.decrementAndGet() > 0;
199     }
200
201
202 }