Merge "Bug 4354 - neutron tenant_id doens't contain '-'(dash)"
[neutron.git] / transcriber / src / main / java / org / opendaylight / neutron / transcriber / AbstractNeutronInterface.java
index b9dcf1efd18e68212a8342b19d0aa49d6bb76aef..2c28d9aa21c16000cc889b76e4406a4d0bc8b0f3 100644 (file)
@@ -9,17 +9,28 @@
 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;
@@ -29,9 +40,10 @@ import com.google.common.base.Optional;
 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;
@@ -50,15 +62,64 @@ public abstract class AbstractNeutronInterface<T extends DataObject, S extends I
         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;
@@ -75,28 +136,77 @@ public abstract class AbstractNeutronInterface<T extends DataObject, S extends I
         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();
@@ -109,6 +219,16 @@ public abstract class AbstractNeutronInterface<T extends DataObject, S extends I
         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;
@@ -168,4 +288,131 @@ public abstract class AbstractNeutronInterface<T extends DataObject, S extends I
 
     }
 
+    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;
+    }
 }