package org.opendaylight.neutron.transcriber;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.neutron.spi.INeutronCRUD;
import org.opendaylight.neutron.spi.INeutronObject;
-public abstract class AbstractNeutronInterface<T extends DataObject, S extends INeutronObject> implements AutoCloseable {
+public abstract class AbstractNeutronInterface<T extends DataObject, U extends ChildOf<? extends DataObject> & Augmentable<U>, S extends INeutronObject> implements AutoCloseable, INeutronCRUD<S>, TransactionChainListener {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractNeutronInterface.class);
private static final int DEDASHED_UUID_LENGTH = 32;
private static final int DEDASHED_UUID_START = 0;
return db;
}
+ public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause) {
+ LOGGER.error("Broken chain {} in TxchainDomWrite, transaction {}, cause {}",
+ chain, transaction.getIdentifier(), cause);
+ }
+
+ public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+ LOGGER.debug("Chain {} closed successfully", chain);
+ }
+
+ protected BindingTransactionChain createTransactionChain() {
+ return getDataBroker().createTransactionChain(this);
+ }
+
+ protected interface Action0<U> {
+ public U action(BindingTransactionChain chain);
+ }
+
+ protected <U> U chainWrapper0(Action0<U> action) {
+ try (BindingTransactionChain chain = this.createTransactionChain()) {
+ return action.action(chain);
+ }
+ }
+
+ protected interface Action1<U, V> {
+ public U action(V input, BindingTransactionChain chain);
+ }
+
+ protected <U, V> U chainWrapper1(V input, Action1<U, V> action) {
+ try (BindingTransactionChain chain = this.createTransactionChain()) {
+ return action.action(input, chain);
+ }
+ }
+
+ protected interface Action2<U, V, W> {
+ public U action(V input0, W input1, BindingTransactionChain chain);
+ }
+
+ protected <U, V, W> U chainWrapper2(V input0, W input1,
+ Action2<U, V, W> action) {
+ try (BindingTransactionChain chain = this.createTransactionChain()) {
+ return action.action(input0, input1, chain);
+ }
+ }
+
protected abstract InstanceIdentifier<T> createInstanceIdentifier(T item);
+ protected abstract InstanceIdentifier<U> createInstanceIdentifier();
+
protected abstract T toMd(S neutronObject);
protected abstract T toMd(String uuid);
- protected <T extends org.opendaylight.yangtools.yang.binding.DataObject> T readMd(InstanceIdentifier<T> path) {
+ protected abstract S fromMd(T dataObject);
+
+ protected <T extends DataObject> T readMd(InstanceIdentifier<T> path, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
T result = null;
- final ReadOnlyTransaction transaction = getDataBroker().newReadOnlyTransaction();
+ final ReadOnlyTransaction transaction = chain.newReadOnlyTransaction();
CheckedFuture<Optional<T>, ReadFailedException> future = transaction.read(LogicalDatastoreType.CONFIGURATION, path);
if (future != null) {
Optional<T> optional;
return result;
}
- protected boolean addMd(S neutronObject) {
+ protected <T extends DataObject> T readMd(InstanceIdentifier<T> path) {
+ return chainWrapper1(path,
+ new Action1<T, InstanceIdentifier<T>>() {
+ @Override
+ public T action(InstanceIdentifier<T> path, BindingTransactionChain chain) {
+ return readMd(path, chain);
+ }
+ });
+ }
+
+ protected boolean addMd(S neutronObject, BindingTransactionChain chain) {
// TODO think about adding existence logic
- return updateMd(neutronObject);
+ return updateMd(neutronObject, chain);
}
- protected boolean updateMd(S neutronObject) {
- WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
- T item = toMd(neutronObject);
- InstanceIdentifier<T> iid = createInstanceIdentifier(item);
- transaction.put(LogicalDatastoreType.CONFIGURATION, iid, item,true);
- CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
- try {
- future.get();
- } catch (InterruptedException | ExecutionException e) {
- LOGGER.warn("Transation failed ",e);
- return false;
+ protected boolean addMd(S neutronObject) {
+ return chainWrapper1(neutronObject,
+ new Action1<Boolean, S>() {
+ @Override
+ public Boolean action(S path, BindingTransactionChain chain) {
+ return addMd(path, chain);
+ }
+ }).booleanValue();
+ }
+
+ protected boolean updateMd(S neutronObject, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+
+ /*
+ * retry for transaction conflict.
+ * see the comment
+ * org.opendaylight.controller.sal.restconf.impl.RestconfImpl#updateConfigurationData
+ */
+ int retries = 2;
+ while (true) {
+ WriteTransaction transaction = chain.newWriteOnlyTransaction();
+ T item = toMd(neutronObject);
+ InstanceIdentifier<T> iid = createInstanceIdentifier(item);
+ transaction.put(LogicalDatastoreType.CONFIGURATION, iid, item, true);
+ CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+ try {
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ if (e.getCause() instanceof OptimisticLockFailedException) {
+ if(--retries >= 0) {
+ LOGGER.debug("Got OptimisticLockFailedException - trying again {}", neutronObject);
+ continue;
+ }
+ LOGGER.warn("Got OptimisticLockFailedException on last try - failing {}", neutronObject);
+ }
+ LOGGER.warn("Transation failed ", e);
+ return false;
+ }
+ break;
}
return true;
}
- protected boolean removeMd(T item) {
- WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
+ protected boolean updateMd(S neutronObject) {
+ return chainWrapper1(neutronObject,
+ new Action1<Boolean, S>() {
+ @Override
+ public Boolean action(S neutronObject, BindingTransactionChain chain) {
+ return updateMd(neutronObject, chain);
+ }
+ }).booleanValue();
+ }
+
+ private boolean removeMd(T item, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+ WriteTransaction transaction = chain.newWriteOnlyTransaction();
InstanceIdentifier<T> iid = createInstanceIdentifier(item);
transaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
return true;
}
+ protected boolean removeMd(T item) {
+ return chainWrapper1(item,
+ new Action1<Boolean, T>() {
+ @Override
+ public Boolean action(T item, BindingTransactionChain chain) {
+ return removeMd(item, chain);
+ }
+ }).booleanValue();
+ }
+
protected Uuid toUuid(String uuid) {
Preconditions.checkNotNull(uuid);
Uuid result;
}
+ protected boolean exists(String uuid, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+ T dataObject = readMd(createInstanceIdentifier(toMd(uuid)), chain);
+ return dataObject != null;
+ }
+
+ @Override
+ public boolean exists(String uuid) {
+ return chainWrapper1(uuid,
+ new Action1<Boolean, String>() {
+ @Override
+ public Boolean action(String uuid, BindingTransactionChain chain) {
+ return exists(uuid, chain);
+ }
+ }).booleanValue();
+ }
+
+ protected S get(String uuid, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+ T dataObject = readMd(createInstanceIdentifier(toMd(uuid)), chain);
+ if (dataObject == null) {
+ return null;
+ }
+ return fromMd(dataObject);
+ }
+
+ @Override
+ public S get(String uuid) {
+ return chainWrapper1(uuid,
+ new Action1<S, String>() {
+ @Override
+ public S action(String uuid, BindingTransactionChain chain) {
+ return get(uuid, chain);
+ }
+ });
+ }
+
+ protected abstract List<T> getDataObjectList(U dataObjects);
+
+ protected List<S> getAll(BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+ Set<S> allNeutronObjects = new HashSet<S>();
+ U dataObjects = readMd(createInstanceIdentifier(), chain);
+ if (dataObjects != null) {
+ for (T dataObject: getDataObjectList(dataObjects)) {
+ allNeutronObjects.add(fromMd(dataObject));
+ }
+ }
+ LOGGER.debug("Exiting _getAll, Found {} OpenStackFirewall", allNeutronObjects.size());
+ List<S> ans = new ArrayList<S>();
+ ans.addAll(allNeutronObjects);
+ return ans;
+ }
+
+ @Override
+ public List<S> getAll() {
+ return chainWrapper0(new Action0<List<S>>() {
+ @Override
+ public List<S> action(BindingTransactionChain chain) {
+ return getAll(chain);
+ }
+ });
+ }
+
+ protected boolean add(S input, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+ if (exists(input.getID(), chain)) {
+ return false;
+ }
+ addMd(input, chain);
+ return true;
+ }
+
+ @Override
+ public boolean add(S input) {
+ return chainWrapper1(input,
+ new Action1<Boolean, S>() {
+ @Override
+ public Boolean action(S input, BindingTransactionChain chain) {
+ return add(input, chain);
+ }
+ }).booleanValue();
+ }
+
+ protected boolean remove(String uuid, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+ if (!exists(uuid, chain)) {
+ return false;
+ }
+ return removeMd(toMd(uuid), chain);
+ }
+
+ @Override
+ public boolean remove(String uuid) {
+ return chainWrapper1(uuid,
+ new Action1<Boolean, String>() {
+ @Override
+ public Boolean action(String uuid, BindingTransactionChain chain) {
+ return remove(uuid, chain);
+ }
+ }).booleanValue();
+ }
+
+ protected boolean update(String uuid, S delta, BindingTransactionChain chain) {
+ Preconditions.checkNotNull(chain);
+ if (!exists(uuid, chain)) {
+ return false;
+ }
+ updateMd(delta, chain);
+ return true;
+ }
+
+ @Override
+ public boolean update(String uuid, S delta) {
+ return chainWrapper2(uuid, delta,
+ new Action2<Boolean, String, S>() {
+ @Override
+ public Boolean action(String uuid, S delta, BindingTransactionChain chain) {
+ return update(uuid, delta, chain);
+ }
+ }).booleanValue();
+ }
+
+ @Override
+ public boolean inUse(String uuid) {
+ return false;
+ }
}