X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fconnect%2Fnetconf%2Fsal%2Ftx%2FAbstractWriteTx.java;fp=opendaylight%2Fmd-sal%2Fsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fconnect%2Fnetconf%2Fsal%2Ftx%2FAbstractWriteTx.java;h=165d9c452d201b5a123da1869c6eaf3a9ace1c85;hb=8793bf7f2e02e6cd926d58c93c8100df30f57ed9;hp=0000000000000000000000000000000000000000;hpb=b30a2df0721908317c9b4770972b5647dfafd3c7;p=controller.git diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/AbstractWriteTx.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/AbstractWriteTx.java new file mode 100644 index 0000000000..165d9c452d --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/AbstractWriteTx.java @@ -0,0 +1,146 @@ +package org.opendaylight.controller.sal.connect.netconf.sal.tx; + +import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.createEditConfigStructure; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities; +import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps; +import org.opendaylight.controller.sal.connect.util.RemoteDeviceId; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.ModifyAction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public abstract class AbstractWriteTx implements DOMDataWriteTransaction { + protected final RemoteDeviceId id; + protected final NetconfBaseOps netOps; + protected final DataNormalizer normalizer; + protected final NetconfSessionCapabilities netconfSessionPreferences; + // Allow commit to be called only once + protected boolean finished = false; + + public AbstractWriteTx(final NetconfBaseOps netOps, final RemoteDeviceId id, final DataNormalizer normalizer, final NetconfSessionCapabilities netconfSessionPreferences) { + this.netOps = netOps; + this.id = id; + this.normalizer = normalizer; + this.netconfSessionPreferences = netconfSessionPreferences; + init(); + } + + protected void checkNotFinished() { + Preconditions.checkState(!isFinished(), "%s: Transaction %s already finished", id, getIdentifier()); + } + + protected boolean isFinished() { + return finished; + } + + protected void invokeBlocking(final String msg, final Function>> op) throws NetconfDocumentedException { + try { + final RpcResult compositeNodeRpcResult = op.apply(netOps).get(1L, TimeUnit.MINUTES); + if(compositeNodeRpcResult.isSuccessful() == false) { + throw new NetconfDocumentedException(id + ": " + msg + " failed: " + compositeNodeRpcResult.getErrors(), NetconfDocumentedException.ErrorType.application, + NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorSeverity.warning); + } + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } catch (final ExecutionException | TimeoutException e) { + throw new NetconfDocumentedException(id + ": " + msg + " failed: " + e.getMessage(), e, NetconfDocumentedException.ErrorType.application, + NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorSeverity.warning); + } + } + + @Override + public synchronized boolean cancel() { + if(isFinished()) { + return false; + } + + finished = true; + cleanup(); + return true; + } + + protected abstract void init(); + + protected abstract void cleanup(); + + @Override + public Object getIdentifier() { + return this; + } + + @Override + public synchronized void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode data) { + checkEditable(store); + + try { + final YangInstanceIdentifier legacyPath = ReadOnlyTx.toLegacyPath(normalizer, path, id); + final CompositeNode legacyData = normalizer.toLegacy(path, data); + editConfig( + createEditConfigStructure(legacyPath, Optional.of(ModifyAction.REPLACE), Optional.fromNullable(legacyData)), Optional.of(ModifyAction.NONE)); + } catch (final NetconfDocumentedException e) { + handleEditException(path, data, e, "putting"); + } + } + + protected abstract void handleEditException(YangInstanceIdentifier path, NormalizedNode data, NetconfDocumentedException e, String editType); + protected abstract void handleDeleteException(YangInstanceIdentifier path, NetconfDocumentedException e); + + @Override + public synchronized void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode data) { + checkEditable(store); + + try { + final YangInstanceIdentifier legacyPath = ReadOnlyTx.toLegacyPath(normalizer, path, id); + final CompositeNode legacyData = normalizer.toLegacy(path, data); + editConfig( + createEditConfigStructure(legacyPath, Optional.absent(), Optional.fromNullable(legacyData)), Optional.absent()); + } catch (final NetconfDocumentedException e) { + handleEditException(path, data, e, "merge"); + } + } + + @Override + public synchronized void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + checkEditable(store); + + try { + editConfig(createEditConfigStructure( + ReadOnlyTx.toLegacyPath(normalizer, path, id), Optional.of(ModifyAction.DELETE), + Optional.absent()), Optional.of(ModifyAction.NONE)); + } catch (final NetconfDocumentedException e) { + handleDeleteException(path, e); + } + } + + @Override + public final ListenableFuture> commit() { + checkNotFinished(); + finished = true; + + return performCommit(); + } + + protected abstract ListenableFuture> performCommit(); + + private void checkEditable(final LogicalDatastoreType store) { + checkNotFinished(); + Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can edit only configuration data, not %s", store); + } + + protected abstract void editConfig(CompositeNode editStructure, Optional defaultOperation) throws NetconfDocumentedException; +}