org.opendaylight.ovsdb.hwvtepsouthbound.transact.AbstractTransactCommand Maven / Gradle / Ivy
/*
* Copyright © 2015, 2017 China Telecom Beijing Research Institute and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
import com.google.common.collect.Lists;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.DataObjectModification;
import org.opendaylight.mdsal.binding.api.DataTreeModification;
import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepTableReader;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.Identifiable;
import org.opendaylight.yangtools.yang.binding.Identifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractTransactCommand, I extends Identifier,
A extends Augmentation> implements TransactCommand {
private static final Logger LOG = LoggerFactory.getLogger(AbstractTransactCommand.class);
protected static final UUID TXUUID = new UUID("TXUUID");
protected volatile HwvtepOperationalState hwvtepOperationalState = null;
protected volatile TransactionBuilder deviceTransaction = null;
private Collection> changes;
Set> updates = new HashSet<>();
protected AbstractTransactCommand() {
// NO OP
}
public AbstractTransactCommand(final HwvtepOperationalState state,
final Collection> changes) {
this.hwvtepOperationalState = state;
this.changes = changes;
}
public HwvtepOperationalState getOperationalState() {
return hwvtepOperationalState;
}
public DataBroker getDataBroker() {
return getOperationalState().getDataBroker();
}
public Collection> getChanges() {
return changes;
}
void updateCurrentTxDeleteData(final Class extends Identifiable> cls, final InstanceIdentifier key,
final T data) {
hwvtepOperationalState.updateCurrentTxDeleteData(cls, key);
markKeyAsInTransit(cls, key);
addToUpdates(key, data);
}
void updateCurrentTxData(final Class extends Identifiable> cls, final InstanceIdentifier key, final UUID uuid,
final T data) {
hwvtepOperationalState.updateCurrentTxData(cls, key, uuid);
markKeyAsInTransit(cls, key);
addToUpdates(key, data);
}
void addToUpdates(final InstanceIdentifier key, final T data) {
T oldData = null;
Type type = getClass().getGenericSuperclass();
Type classType = ((ParameterizedType) type).getActualTypeArguments()[0];
if (getConfigData((Class extends Identifiable>) classType, key) != null) {
oldData = (T) getConfigData((Class extends Identifiable>) classType, key).getData();
}
updates.add(new MdsalUpdate<>(key, data, oldData));
}
void processDependencies(final UnMetDependencyGetter unMetDependencyGetter,
final TransactionBuilder transaction,
final InstanceIdentifier nodeIid,
final InstanceIdentifier key,
final T data, final Object... extraData) {
HwvtepDeviceInfo deviceInfo = hwvtepOperationalState.getDeviceInfo();
Type type = getClass().getGenericSuperclass();
Type classType = ((ParameterizedType) type).getActualTypeArguments()[0];
Map inTransitDependencies = Collections.emptyMap();
Map confingDependencies = Collections.emptyMap();
if (isDeleteCmd()) {
if (deviceInfo.isKeyInTransit((Class extends Identifiable>) classType, key)) {
inTransitDependencies = new HashMap<>();
inTransitDependencies.put(classType, Lists.newArrayList(key));
}
} else {
inTransitDependencies = unMetDependencyGetter.getInTransitDependencies(hwvtepOperationalState, data);
confingDependencies = unMetDependencyGetter.getUnMetConfigDependencies(hwvtepOperationalState, data);
//we can skip the config termination point dependency as we can create them in device as part of this tx
confingDependencies.remove(TerminationPoint.class);
//If this key itself is in transit wait for the response of this key itself
if (deviceInfo.isKeyInTransit((Class extends Identifiable>) classType, key)
|| deviceInfo.isKeyInDependencyQueue(key)) {
inTransitDependencies.put(classType, Lists.newArrayList(key));
}
}
LOG.info("Update received for key: {} txId: {}", key, getOperationalState().getTransactionId());
if (HwvtepSouthboundUtil.isEmptyMap(confingDependencies)
&& HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
doDeviceTransaction(transaction, nodeIid, data, key, extraData);
if (isDeleteCmd()) {
getDeviceInfo().clearConfigData((Class extends Identifiable>) classType, key);
} else {
getDeviceInfo().updateConfigData((Class extends Identifiable>) classType, key, data);
}
}
if (!HwvtepSouthboundUtil.isEmptyMap(confingDependencies)) {
DependentJob configWaitingJob = new DependentJob.ConfigWaitingJob(
key, data, confingDependencies) {
AbstractTransactCommand clone = getClone();
@Override
public void onDependencyResolved(final HwvtepOperationalState operationalState,
final TransactionBuilder transactionBuilder) {
clone.hwvtepOperationalState = operationalState;
HwvtepDeviceInfo.DeviceData deviceData =
getDeviceInfo().getConfigData((Class extends Identifiable>)getClassType(), key);
T latest = data;
if (deviceData != null && deviceData.getData() != null) {
latest = (T) deviceData.getData();
clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
} else if (isDeleteCmd()) {
clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
}
}
@Override
public void onFailure() {
clone.onFailure(transaction);
}
@Override
public void onSuccess() {
clone.onSuccess(transaction);
}
};
LOG.info("Update Adding to config wait queue for key: {} txId: {}",
key, getOperationalState().getTransactionId());
addJobToQueue(configWaitingJob);
return;
}
final long transactionId = hwvtepOperationalState.getTransactionId();
if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
DependentJob opWaitingJob = new DependentJob.OpWaitingJob(
key, data, inTransitDependencies, transactionId) {
AbstractTransactCommand clone = getClone();
@Override
public void onDependencyResolved(final HwvtepOperationalState operationalState,
final TransactionBuilder transactionBuilder) {
clone.hwvtepOperationalState = operationalState;
HwvtepDeviceInfo.DeviceData deviceData = getDeviceInfo()
.getConfigData((Class extends Identifiable>)getClassType(), key);
T latest = data;
if (deviceData != null && deviceData.getData() != null) {
latest = (T) deviceData.getData();
clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
} else if (isDeleteCmd()) {
clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
}
}
@Override
public void onFailure() {
clone.onFailure(transaction);
}
@Override
public void onSuccess() {
clone.onSuccess(transaction);
}
};
LOG.info("Update Adding to op wait queue for key: {} txId: {}", key, transactionId);
addJobToQueue(opWaitingJob);
return;
}
}
@Override
public void doDeviceTransaction(final TransactionBuilder transaction, final InstanceIdentifier nodeIid,
final T data, final InstanceIdentifier key, final Object... extraData) {
//tobe removed as part of refactoring patch
}
@Override
public void onConfigUpdate(final TransactionBuilder transaction, final InstanceIdentifier nodeIid,
final T data, final InstanceIdentifier key, final Object... extraData) {
//tobe removed as part of refactoring patch
}
protected A augmentation(final Node node) {
if (node == null) {
return null;
}
ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
Class extends Augmentation> augType =
(Class extends Augmentation>) parameterizedType.getActualTypeArguments()[1];
Augmentation augmentation = node.augmentation(augType);
return (A) augmentation;
}
protected Map getData(final A augmentation) {
return Collections.emptyMap();
}
protected List getData(final Node node) {
A augmentation = augmentation(node);
if (augmentation != null) {
Map data = getData(augmentation);
if (data != null) {
// TODO: why are we performing a copy here?
return new ArrayList<>(data.values());
}
}
return Collections.emptyList();
}
@NonNull
protected Map, List> extractRemoved(
final Collection> modification, final Class class1) {
Map, List> result = new HashMap<>();
if (modification != null && !modification.isEmpty()) {
for (DataTreeModification change : modification) {
final InstanceIdentifier key = change.getRootPath().getRootIdentifier();
if (!Objects.equals(hwvtepOperationalState.getConnectionInstance().getInstanceIdentifier(), key)) {
continue;
}
Class extends Identifiable> classType = (Class extends Identifiable>) getClassType();
List removed;
if (getOperationalState().isInReconciliation()) {
removed = getRemoved(change);
} else {
removed = (List) getOperationalState().getDeletedData(key, classType);
}
removed.addAll(getCascadeDeleteData(change));
result.put(key, removed);
}
}
return result;
}
@NonNull
protected Map, List> extractUpdated(
final Collection> modification, final Class class1) {
Map, List> result = new HashMap<>();
if (modification != null && !modification.isEmpty()) {
for (DataTreeModification change : modification) {
InstanceIdentifier key = change.getRootPath().getRootIdentifier();
if (!Objects.equals(hwvtepOperationalState.getConnectionInstance().getInstanceIdentifier(), key)) {
continue;
}
Class extends Identifiable> classType = (Class extends Identifiable>) getClassType();
List updated = null;
if (getOperationalState().isInReconciliation()) {
updated = getUpdated(change);
} else {
updated = (List) getOperationalState().getUpdatedData(key, classType);
}
result.put(key, updated);
}
}
return result;
}
List getCascadeDeleteData(final DataTreeModification change) {
if (!cascadeDelete()) {
return Collections.emptyList();
}
DataObjectModification mod = change.getRootNode();
Node updatedNode = TransactUtils.getUpdated(mod);
List updatedData = getData(updatedNode);
Set deleted = getOperationalState().getDeletedKeysInCurrentTx(LogicalSwitches.class);
UnMetDependencyGetter dependencyGetter = getDependencyGetter();
if (!HwvtepSouthboundUtil.isEmpty(deleted) && !HwvtepSouthboundUtil.isEmpty(updatedData)
&& dependencyGetter != null) {
List removed = new ArrayList<>();
for (T ele : updatedData) {
if (deleted.containsAll(dependencyGetter.getLogicalSwitchDependencies(ele))) {
removed.add(ele);
}
}
return removed;
}
return Collections.emptyList();
}
List getRemoved(final DataTreeModification change) {
DataObjectModification mod = change.getRootNode();
Node removed = TransactUtils.getRemoved(mod);
Node updated = TransactUtils.getUpdated(mod);
Node before = mod.getDataBefore();
return diffOf(removed, before, updated, true);
}
List getUpdated(final DataTreeModification change) {
DataObjectModification mod = change.getRootNode();
Node updated = TransactUtils.getUpdated(mod);
Node before = mod.getDataBefore();
return diffOf(updated, before, false);
}
List diffOf(final Node include, final Node node1, final Node node2, final boolean compareKeyOnly) {
List data1 = getData(include);
List data2 = diffOf(node1, node2, compareKeyOnly);
if (HwvtepSouthboundUtil.isEmpty(data1) && HwvtepSouthboundUtil.isEmpty(data2)) {
return Collections.EMPTY_LIST;
}
List result = new ArrayList<>(data1);
result.addAll(data2);
return result;
}
List diffOf(final Node node1, final Node node2, final boolean compareKeyOnly) {
List result = new ArrayList<>();
List list1 = getData(node1);
List list2 = getData(node2);
if (HwvtepSouthboundUtil.isEmpty(list1)) {
return Collections.EMPTY_LIST;
}
if (HwvtepSouthboundUtil.isEmpty(list2)) {
return HwvtepSouthboundUtil.isEmpty(list1) ? Collections.EMPTY_LIST : list1;
}
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy