import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.Rfc8040.IetfYangLibrary;
import org.opendaylight.restconf.nb.rfc8040.Rfc8040.MonitoringModule;
private void putData(
final NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>> normNode) {
- final DOMDataTreeWriteTransaction wTx = this.transactionChainHandler.get().newWriteOnlyTransaction();
+ final DOMTransactionChain transactionChain = this.transactionChainHandler.get();
+ final DOMDataTreeWriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
wTx.put(LogicalDatastoreType.OPERATIONAL,
YangInstanceIdentifier.create(NodeIdentifier.create(normNode.getNodeType())), normNode);
try {
* This is workaround for bug https://bugs.opendaylight.org/show_bug.cgi?id=7728
*/
LOG.warn("Ignoring that another cluster node is already putting the same data to DS.", e);
- this.transactionChainHandler.reset();
} else {
throw new RestconfDocumentedException("Problem occurred while putting data to DS.", failure);
}
+ } finally {
+ transactionChain.close();
}
}
}
package org.opendaylight.restconf.nb.rfc8040.handlers;
import java.util.Objects;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
public void onTransactionChainFailed(final DOMTransactionChain chain, final DOMDataTreeTransaction transaction,
final Throwable cause) {
LOG.warn("TransactionChain({}) {} FAILED!", chain, transaction.getIdentifier(), cause);
- reset();
+ transactionChainList.remove(chain);
throw new RestconfDocumentedException("TransactionChain(" + chain + ") not committed correctly", cause);
}
@Override
public void onTransactionChainSuccessful(final DOMTransactionChain chain) {
LOG.trace("TransactionChain({}) SUCCESSFUL", chain);
+ transactionChainList.remove(chain);
}
};
private final DOMDataBroker dataBroker;
-
- private volatile DOMTransactionChain transactionChain;
+ private final Queue<DOMTransactionChain> transactionChainList;
/**
* Prepare transaction chain service for Restconf services.
@Inject
public TransactionChainHandler(final DOMDataBroker dataBroker) {
this.dataBroker = Objects.requireNonNull(dataBroker);
- transactionChain = Objects.requireNonNull(dataBroker.createTransactionChain(transactionChainListener));
+ this.transactionChainList = new ConcurrentLinkedQueue<>();
}
+ /**
+ * Create and return new instance of object {@link DOMTransactionChain}.
+ * After use, is important to close transactionChain by method {@link DOMTransactionChain#close()}.
+ * @return new instance of object {@link DOMTransactionChain}
+ */
@Override
public DOMTransactionChain get() {
- return this.transactionChain;
- }
-
- public synchronized void reset() {
- LOG.trace("Resetting TransactionChain({})", transactionChain);
- transactionChain.close();
- transactionChain = dataBroker.createTransactionChain(transactionChainListener);
+ final DOMTransactionChain transactionChain = dataBroker.createTransactionChain(transactionChainListener);
+ this.transactionChainList.add(transactionChain);
+ LOG.trace("Started TransactionChain({})", transactionChain);
+ return transactionChain;
}
@Override
@PreDestroy
public synchronized void close() {
- transactionChain.close();
+ for (DOMTransactionChain transactionChain: this.transactionChainList) {
+ transactionChain.close();
+ LOG.trace("Closed TransactionChain({})", transactionChain);
+ }
+ }
+
+ /**
+ * Verify if {@link DOMTransactionChain} exist in {@link TransactionChainHandler} queue.
+ * @param transactionChain object to check.
+ * @return true if object still exist in {@link TransactionChainHandler}.
+ */
+ boolean verifyIfExistTransactionChain(DOMTransactionChain transactionChain) {
+ return this.transactionChainList.contains(transactionChain);
}
}
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
* @return {@link Response}
*/
public static Response deleteData(final TransactionVarsWrapper transactionNode) {
- final FluentFuture<? extends CommitInfo> future = submitData(transactionNode.getTransactionChainHandler(),
+ final DOMTransactionChain transactionChain = transactionNode.getTransactionChainHandler().get();
+ final FluentFuture<? extends CommitInfo> future = submitData(transactionChain,
transactionNode.getInstanceIdentifier().getInstanceIdentifier());
final ResponseFactory response = new ResponseFactory(Status.NO_CONTENT);
- FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE, response);
+ //This method will close transactionChain
+ FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE, response,
+ transactionChain);
return response.build();
}
/**
* Delete data via transaction. Return error if data to delete does not exist.
*
- * @param transactionChainHandler
- * transaction chain handler
- * @param readWriteTx
- * read and write transaction
+ * @param transactionChain
+ * transaction chain
* @param path
* path of data to delete
* @return {@link FluentFuture}
*/
private static FluentFuture<? extends CommitInfo> submitData(
- final TransactionChainHandler transactionChainHandler, final YangInstanceIdentifier path) {
- final DOMDataTreeReadWriteTransaction readWriteTx = transactionChainHandler.get().newReadWriteTransaction();
- TransactionUtil.checkItemExists(transactionChainHandler, readWriteTx, LogicalDatastoreType.CONFIGURATION, path,
+ final DOMTransactionChain transactionChain, final YangInstanceIdentifier path) {
+ final DOMDataTreeReadWriteTransaction readWriteTx = transactionChain.newReadWriteTransaction();
+ TransactionUtil.checkItemExists(transactionChain, readWriteTx, LogicalDatastoreType.CONFIGURATION, path,
RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE);
readWriteTx.delete(LogicalDatastoreType.CONFIGURATION, path);
return readWriteTx.commit();
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
import java.util.concurrent.ExecutionException;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
import org.opendaylight.mdsal.dom.api.DOMActionException;
import org.opendaylight.mdsal.dom.api.DOMRpcException;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
import org.opendaylight.netconf.api.NetconfDocumentedException;
*/
@SuppressWarnings("checkstyle:IllegalCatch")
static <T> void addCallback(final ListenableFuture<T> listenableFuture, final String txType,
- final FutureDataFactory<? super T> dataFactory) throws RestconfDocumentedException {
+ final FutureDataFactory<? super T> dataFactory) throws RestconfDocumentedException {
+ addCallback(listenableFuture,txType,dataFactory,null);
+ }
+
+ /**
+ * Add callback to the future object and close transaction chain.
+ *
+ * @param listenableFuture
+ * future object
+ * @param txType
+ * type of operation (READ, POST, PUT, DELETE)
+ * @param dataFactory
+ * factory setting result
+ * @param transactionChain
+ * transaction chain
+ * @throws RestconfDocumentedException
+ * if the Future throws an exception
+ */
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ static <T> void addCallback(final ListenableFuture<T> listenableFuture, final String txType,
+ final FutureDataFactory<? super T> dataFactory, @Nullable final DOMTransactionChain transactionChain)
+ throws RestconfDocumentedException {
try {
final T result = listenableFuture.get();
} else {
throw new RestconfDocumentedException("Transaction failed", e);
}
+ } finally {
+ if (transactionChain != null) {
+ transactionChain.close();
+ }
}
}
}
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
}
/**
- * Process edit operations of one {@link PatchContext}.
+ * Process edit operations of one {@link PatchContext}. Close {@link DOMTransactionChain} inside of object
+ * {@link TransactionVarsWrapper} provided as a parameter.
* @param context Patch context to be processed
* @param transactionNode Wrapper for transaction
* @param schemaContextRef Soft reference for global schema context
final SchemaContextRef schemaContextRef) {
final List<PatchStatusEntity> editCollection = new ArrayList<>();
boolean noError = true;
- final DOMDataTreeReadWriteTransaction tx = transactionNode.getTransactionChain().newReadWriteTransaction();
+ final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
+ final DOMDataTreeReadWriteTransaction tx = transactionChain.newReadWriteTransaction();
for (final PatchEntity patchEntity : context.getData()) {
if (noError) {
final FluentFuture<? extends CommitInfo> future = tx.commit();
try {
- FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
+ //This method will close transactionChain
+ FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response, transactionChain);
} catch (final RestconfDocumentedException e) {
// if errors occurred during transaction commit then patch failed and global errors are reported
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false,
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), true, null);
} else {
tx.cancel();
- transactionNode.getTransactionChainHandler().reset();
+ transactionChain.close();
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection),
false, null);
}
* @param dataStore Datastore to write data to
* @param path Path for data to be created
* @param payload Data to be created
- * @param rWTransaction Transaction
+ * @param rwTransaction Transaction
* @param schemaContextRef Soft reference for global schema context
*/
private static void createDataWithinTransaction(final LogicalDatastoreType dataStore,
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
}
/**
- * Check mount point and prepare variables for post data.
+ * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} inside of object
+ * {@link TransactionVarsWrapper} provided as a parameter.
*
* @param uriInfo
*
transactionNode, schemaContextRef.get(), insert, point);
final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
- FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
+ //This method will close transactionChain
+ FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory,
+ transactionNode.getTransactionChain());
return dataFactory.build();
}
private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
final SchemaContext schemaContext, final String insert, final String point) {
- final DOMTransactionChain domTransactionChain = transactionNode.getTransactionChain();
- final DOMDataTreeReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction();
+ final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
+ final DOMDataTreeReadWriteTransaction newReadWriteTransaction = transactionChain.newReadWriteTransaction();
if (insert == null) {
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(), newReadWriteTransaction);
+ makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
return newReadWriteTransaction.commit();
} else {
final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
+ makePost(path, data, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
} else {
newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
path.getParent().getParent());
simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
- schemaContext, transactionNode.getTransactionChainHandler());
- makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
+ schemaContext, transactionChain);
+ makePost(path, readData, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
}
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
+ makePost(path, data, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
} else {
newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
path.getParent().getParent());
simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
- schemaContext, transactionNode.getTransactionChainHandler());
- makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
+ schemaContext, transactionChain);
+ makePost(path, readData, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
}
}
case "last":
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
+ makePost(path, data, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
case "before":
schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
+ makePost(path, data, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
} else {
insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
data, schemaContext, point, readList, true,
- transactionNode.getTransactionChainHandler());
+ transactionChain);
return newReadWriteTransaction.commit();
}
} else {
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
+ makePost(path, data, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
} else {
insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
path, data, schemaContext, point, readLeafList, true,
- transactionNode.getTransactionChainHandler());
+ transactionChain);
return newReadWriteTransaction.commit();
}
}
schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
+ makePost(path, data, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
} else {
insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
data, schemaContext, point, readList, false,
- transactionNode.getTransactionChainHandler());
+ transactionChain);
return newReadWriteTransaction.commit();
}
} else {
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
+ makePost(path, data, schemaContext, transactionChain,
newReadWriteTransaction);
return newReadWriteTransaction.commit();
} else {
insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
path, data, schemaContext, point, readLeafList, true,
- transactionNode.getTransactionChainHandler());
+ transactionChain);
return newReadWriteTransaction.commit();
}
}
private static void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
- final boolean before, final TransactionChainHandler transactionChainHandler) {
+ final boolean before, final DOMTransactionChain transactionChain) {
rwTransaction.delete(datastore, path.getParent().getParent());
final InstanceIdentifierContext<?> instanceIdentifier =
ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
+ TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
rwTransaction.put(datastore, path, payload);
}
final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
- TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, childPath,
+ TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
rwTransaction.put(datastore, childPath, nodeChild);
lastInsertedPosition++;
private static void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
- final TransactionChainHandler transactionChainHandler) {
+ final DOMTransactionChain transactionChain) {
rwTransaction.delete(datastore, path.getParent().getParent());
final InstanceIdentifierContext<?> instanceIdentifier =
ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
for (final MapEntryNode mapEntryNode : readList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
+ TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
rwTransaction.put(datastore, path, payload);
}
final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
- TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, childPath,
+ TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
rwTransaction.put(datastore, childPath, mapEntryNode);
lastInsertedPosition++;
}
private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
- final SchemaContext schemaContext, final TransactionChainHandler transactionChainHandler,
+ final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
final DOMDataTreeReadWriteTransaction transaction) {
if (data instanceof MapNode) {
boolean merge = false;
for (final MapEntryNode child : ((MapNode) data).getValue()) {
final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
TransactionUtil.checkItemDoesNotExists(
- transactionChainHandler, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
+ transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
if (!merge) {
merge = true;
}
} else {
TransactionUtil.checkItemDoesNotExists(
- transactionChainHandler, transaction, LogicalDatastoreType.CONFIGURATION, path,
+ transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
private static void simplePost(final DOMDataTreeReadWriteTransaction rwTransaction,
final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
- final SchemaContext schemaContext, final TransactionChainHandler transactionChainHandler) {
- TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
+ final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
+ TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
rwTransaction.put(datastore, path, payload);
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
}
/**
- * Check mount point and prepare variables for put data to DS.
+ * Check mount point and prepare variables for put data to DS. Close {@link DOMTransactionChain} inside of object
+ * {@link TransactionVarsWrapper} provided as a parameter.
*
* @param payload
* data to put
new ResponseFactory(existsResponse.result ? Status.NO_CONTENT : Status.CREATED);
final FluentFuture<? extends CommitInfo> submitData = submitData(path, schemaContext,
transactionNode.getTransactionChainHandler(), readWriteTransaction, payload.getData(), insert, point);
- FutureCallbackTx.addCallback(submitData, RestconfDataServiceConstant.PutData.PUT_TX_TYPE, responseFactory);
+ //This method will close transactionChain
+ FutureCallbackTx.addCallback(submitData, RestconfDataServiceConstant.PutData.PUT_TX_TYPE, responseFactory,
+ transactionNode.getTransactionChain());
return responseFactory.build();
}
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.WriterParameters;
import org.opendaylight.restconf.common.context.WriterParameters.WriterParametersBuilder;
}
/**
- * Read specific type of data from data store via transaction.
+ * Read specific type of data from data store via transaction. Close {@link DOMTransactionChain} inside of object
+ * {@link TransactionVarsWrapper} provided as a parameter.
*
* @param valueOfContent
* type of data to read (config, state, all)
return readAllData(transactionNode, withDefa, ctx);
default:
+ transactionNode.getTransactionChain().close();
throw new RestconfDocumentedException(
new RestconfError(RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.INVALID_VALUE,
"Invalid content parameter: " + valueOfContent, null,
/**
* If is set specific {@link LogicalDatastoreType} in
* {@link TransactionVarsWrapper}, then read this type of data from DS. If
- * don't, we have to read all data from DS (state + config)
+ * don't, we have to read all data from DS (state + config).
+ * This method will close {@link org.opendaylight.mdsal.dom.api.DOMTransactionChain} inside of
+ * {@link TransactionVarsWrapper}.
*
* @param transactionNode
* {@link TransactionVarsWrapper} - wrapper for variables
*/
private static @Nullable NormalizedNode<?, ?> readDataViaTransaction(
final @NonNull TransactionVarsWrapper transactionNode) {
+ return readDataViaTransaction(transactionNode, true);
+ }
+
+
+ /**
+ * If is set specific {@link LogicalDatastoreType} in
+ * {@link TransactionVarsWrapper}, then read this type of data from DS. If
+ * don't, we have to read all data from DS (state + config)
+ *
+ * @param transactionNode
+ * {@link TransactionVarsWrapper} - wrapper for variables
+ * @param closeTransactionChain
+ * If is set to true, after transaction it will close transactionChain in {@link TransactionVarsWrapper}
+ * @return {@link NormalizedNode}
+ */
+ private static @Nullable NormalizedNode<?, ?> readDataViaTransaction(
+ final @NonNull TransactionVarsWrapper transactionNode, final boolean closeTransactionChain) {
final NormalizedNodeFactory dataFactory = new NormalizedNodeFactory();
try (DOMDataTreeReadTransaction tx = transactionNode.getTransactionChain().newReadOnlyTransaction()) {
final FluentFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = tx.read(
transactionNode.getLogicalDatastoreType(),
transactionNode.getInstanceIdentifier().getInstanceIdentifier());
- FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
- dataFactory);
+ if (closeTransactionChain) {
+ //Method close transactionChain inside of TransactionVarsWrapper, if is provide as a parameter.
+ FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
+ dataFactory, transactionNode.getTransactionChain());
+ } else {
+ FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
+ dataFactory);
+ }
}
return dataFactory.build();
}
/**
- * Read config and state data, then map them.
+ * Read config and state data, then map them. Close {@link DOMTransactionChain} inside of object
+ * {@link TransactionVarsWrapper} provided as a parameter.
*
* @param transactionNode
* {@link TransactionVarsWrapper} - wrapper for variables
final String withDefa, final SchemaContext ctx) {
// PREPARE STATE DATA NODE
transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
- final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(transactionNode);
+ final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(transactionNode, false);
// PREPARE CONFIG DATA NODE
transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
final NormalizedNode<?, ?> configDataNode;
+ //Here will be closed transactionChain
if (withDefa == null) {
configDataNode = readDataViaTransaction(transactionNode);
} else {
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMNotificationListener;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
ErrorTag.UNKNOWN_ELEMENT);
}
- final DOMDataTreeReadWriteTransaction writeTransaction = handlersHolder
- .getTransactionChainHandler()
- .get()
- .newReadWriteTransaction();
+ final DOMTransactionChain transactionChain = handlersHolder.getTransactionChainHandler().get();
+ final DOMDataTreeReadWriteTransaction writeTransaction = transactionChain.newReadWriteTransaction();
final SchemaContext schemaContext = handlersHolder.getSchemaHandler().get();
final boolean exist = checkExist(schemaContext, writeTransaction);
final URI uri = prepareUriByStreamName(uriInfo, streamName);
notificationListenerAdapter.get().getSchemaPath().getLastComponent().getLocalName(), writeTransaction,
exist, mapToStreams);
submitData(writeTransaction);
+ transactionChain.close();
return uri;
}
registration(datastoreType, listener.get(), handlersHolder.getDomDataBrokerHandler().get());
final URI uri = prepareUriByStreamName(uriInfo, streamName);
- final DOMDataTreeReadWriteTransaction writeTransaction
- = handlersHolder.getTransactionChainHandler().get().newReadWriteTransaction();
+ final DOMTransactionChain transactionChain = handlersHolder.getTransactionChainHandler().get();
+ final DOMDataTreeReadWriteTransaction writeTransaction = transactionChain.newReadWriteTransaction();
final SchemaContext schemaContext = handlersHolder.getSchemaHandler().get();
final boolean exist = checkExist(schemaContext, writeTransaction);
writeDataToDS(schemaContext, listener.get().getPath().getLastPathArgument().getNodeType().getLocalName(),
writeTransaction, exist, mapToStreams);
submitData(writeTransaction);
+ transactionChain.close();
return uri;
}
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
/**
* Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data does NOT already exists.
- * @param transactionChainHandler Transaction chain handler
+ * @param transactionChain Transaction chain
* @param rwTransaction Transaction
* @param store Datastore
* @param path Path to be checked
* @param operationType Type of operation (READ, POST, PUT, DELETE...)
*/
- public static void checkItemExists(final TransactionChainHandler transactionChainHandler,
+ public static void checkItemExists(final DOMTransactionChain transactionChain,
final DOMDataTreeReadWriteTransaction rwTransaction,
final LogicalDatastoreType store, final YangInstanceIdentifier path,
final String operationType) {
FutureCallbackTx.addCallback(future, operationType, response);
if (!response.result) {
- // close transaction and reset transaction chain
+ // close transaction
rwTransaction.cancel();
- transactionChainHandler.reset();
-
+ transactionChain.close();
// throw error
LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
throw new RestconfDocumentedException(
/**
* Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data already exists.
- * @param transactionChainHandler Transaction chain handler
+ * @param transactionChain Transaction chain
* @param rwTransaction Transaction
* @param store Datastore
* @param path Path to be checked
* @param operationType Type of operation (READ, POST, PUT, DELETE...)
*/
- public static void checkItemDoesNotExists(final TransactionChainHandler transactionChainHandler,
+ public static void checkItemDoesNotExists(final DOMTransactionChain transactionChain,
final DOMDataTreeReadWriteTransaction rwTransaction,
final LogicalDatastoreType store, final YangInstanceIdentifier path,
final String operationType) {
FutureCallbackTx.addCallback(future, operationType, response);
if (response.result) {
- // close transaction and reset transaction chain
+ // close transaction
rwTransaction.cancel();
- transactionChainHandler.reset();
-
+ transactionChain.close();
// throw error
LOG.trace("Operation via Restconf was not executed because data at {} already exists", path);
throw new RestconfDocumentedException(
import javax.xml.transform.stream.StreamResult;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.nb.rfc8040.Rfc8040.MonitoringModule;
import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
* Delete data in DS.
*/
protected void deleteDataInDS() throws Exception {
- final DOMDataTreeWriteTransaction wTx = this.transactionChainHandler.get().newWriteOnlyTransaction();
+ final DOMTransactionChain transactionChain = this.transactionChainHandler.get();
+ final DOMDataTreeWriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
wTx.delete(LogicalDatastoreType.OPERATIONAL, IdentifierCodec
.deserialize(MonitoringModule.PATH_TO_STREAM_WITHOUT_KEY + this.localName, this.schemaHandler.get()));
wTx.commit().get();
+ transactionChain.close();
}
/**
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.restconf.nb.rfc8040.handlers;
+
+import com.google.common.collect.ClassToInstanceMap;
+import org.eclipse.jdt.annotation.NonNull;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+
+public class TransactionChainHandlerTest {
+
+ private TransactionChainHandler transactionChainHandler;
+ private static final String EXCEPTION_MESSAGE = "(TEST) Unsupported Method";
+
+ @After
+ public void shutdown() {
+ this.transactionChainHandler.close();
+ }
+
+ @Test
+ public void transactionChainTest() {
+ this.transactionChainHandler = new TransactionChainHandler(new DataBrokerLocal());
+ final DOMTransactionChain chain1 = this.transactionChainHandler.get();
+ final DOMTransactionChain chain2 = this.transactionChainHandler.get();
+ Assert.assertNotNull(chain1);
+ Assert.assertNotNull(chain2);
+ Assert.assertNotEquals(chain1, chain2);
+ chain1.close();
+ Assert.assertFalse(this.transactionChainHandler.verifyIfExistTransactionChain(chain1));
+
+ try {
+ chain2.newReadOnlyTransaction();
+ } catch (RestconfDocumentedException e) {
+ Assert.assertEquals(e.getCause().getLocalizedMessage(), EXCEPTION_MESSAGE);
+ }
+ Assert.assertFalse(this.transactionChainHandler.verifyIfExistTransactionChain(chain2));
+ }
+
+ private final class TxChainLocal implements DOMTransactionChain {
+ DOMTransactionChainListener listener;
+
+ TxChainLocal(DOMTransactionChainListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public DOMDataTreeReadTransaction newReadOnlyTransaction() {
+ final DOMDataTreeTransaction domDataTreeTransaction = Mockito.mock(DOMDataTreeTransaction.class);
+ listener.onTransactionChainFailed(this,
+ domDataTreeTransaction, new Throwable(EXCEPTION_MESSAGE));
+ return null;
+ }
+
+ @Override
+ public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
+ return null;
+ }
+
+ @Override
+ public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
+ return null;
+ }
+
+ @Override
+ public void close() {
+ listener.onTransactionChainSuccessful(this);
+ }
+ }
+
+ private final class DataBrokerLocal implements DOMDataBroker {
+
+ @Override
+ public @NonNull DOMTransactionChain createTransactionChain(DOMTransactionChainListener listener) {
+ return new TxChainLocal(listener);
+ }
+
+ @Override
+ public @NonNull DOMTransactionChain createMergingTransactionChain(DOMTransactionChainListener listener) {
+ return null;
+ }
+
+ @Override
+ public @NonNull ClassToInstanceMap<DOMDataBrokerExtension> getExtensions() {
+ return null;
+ }
+
+ @Override
+ public DOMDataTreeReadTransaction newReadOnlyTransaction() {
+ return null;
+ }
+
+ @Override
+ public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
+ return null;
+ }
+
+ @Override
+ public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
+ return null;
+ }
+ }
+}