Futures.addCallback(Futures.allAsList(resultsFutures), new FutureCallback<List<DOMRpcResult>>() {
@Override
public void onSuccess(@Nonnull final List<DOMRpcResult> domRpcResults) {
- domRpcResults.forEach(domRpcResult -> {
- if (!domRpcResult.getErrors().isEmpty() && !transformed.isDone()) {
- final NetconfDocumentedException exception =
- new NetconfDocumentedException(id + ":RPC during tx failed",
- DocumentedException.ErrorType.APPLICATION,
- DocumentedException.ErrorTag.OPERATION_FAILED,
- DocumentedException.ErrorSeverity.ERROR);
- transformed.setException(exception);
- }
- });
-
if (!transformed.isDone()) {
- transformed.set(RpcResultBuilder.<Void>success().build());
+ extractResult(domRpcResults, transformed);
}
}
return transformed;
}
+ private void extractResult(final List<DOMRpcResult> domRpcResults,
+ final SettableFuture<RpcResult<Void>> transformed) {
+ for (final DOMRpcResult domRpcResult : domRpcResults) {
+ if (!domRpcResult.getErrors().isEmpty()) {
+ final RpcError error = domRpcResult.getErrors().iterator().next();
+ final RpcError.ErrorType errorType = error.getErrorType();
+ final DocumentedException.ErrorType eType;
+ switch (errorType) {
+ case RPC:
+ eType = DocumentedException.ErrorType.RPC;
+ break;
+ case PROTOCOL:
+ eType = DocumentedException.ErrorType.PROTOCOL;
+ break;
+ case TRANSPORT:
+ eType = DocumentedException.ErrorType.TRANSPORT;
+ break;
+ case APPLICATION:
+ eType = DocumentedException.ErrorType.APPLICATION;
+ break;
+ default:
+ eType = DocumentedException.ErrorType.APPLICATION;
+ break;
+ }
+ final RpcError.ErrorSeverity severity = error.getSeverity();
+ final DocumentedException.ErrorSeverity eSeverity;
+ switch (severity) {
+ case ERROR:
+ eSeverity = DocumentedException.ErrorSeverity.ERROR;
+ break;
+ case WARNING:
+ eSeverity = DocumentedException.ErrorSeverity.WARNING;
+ break;
+ default:
+ eSeverity = DocumentedException.ErrorSeverity.ERROR;
+ break;
+ }
+ final String message;
+ if (error.getMessage() == null || error.getMessage().isEmpty()) {
+ message = id + ":RPC during tx failed";
+ } else {
+ message = error.getMessage();
+ }
+ final NetconfDocumentedException exception = new NetconfDocumentedException(message,
+ eType,
+ DocumentedException.ErrorTag.from(error.getTag()),
+ eSeverity);
+ transformed.setException(exception);
+ return;
+ }
+ }
+
+ transformed.set(RpcResultBuilder.<Void>success().build());
+ }
+
AutoCloseable addListener(final TxListener listener) {
listeners.add(listener);
return () -> listeners.remove(listener);
<dependency>
<groupId>org.opendaylight.netconf</groupId>
<artifactId>restconf-common-models</artifactId>
- </dependency>
+ </dependency>
<dependency>
<groupId>org.opendaylight.netconf</groupId>
<artifactId>restconf-common</artifactId>
- </dependency>
+ </dependency>
<dependency>
<groupId>org.opendaylight.netconf</groupId>
<artifactId>ietf-yang-library</artifactId>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
*/
package org.opendaylight.restconf.nb.rfc8040.rests.utils;
+import com.google.common.base.Throwables;
import com.google.common.util.concurrent.CheckedFuture;
import java.util.ArrayList;
import java.util.List;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.api.NetconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
rpcErrorList.add(
RpcResultBuilder.newError(RpcError.ErrorType.RPC, "operation-failed", e.getMessage()));
dataFactory.setResult((T) new DefaultDOMRpcResult(rpcErrorList));
+ } else if (e instanceof TransactionCommitFailedException) {
+ /* If device send some error message we want this message to get to client
+ and not just to throw it away or override it with new generic message.
+ We search for NetconfDocumentedException that was send from netconfSB
+ and we create RestconfDocumentedException accordingly.
+ */
+ final List<Throwable> causalChain = Throwables.getCausalChain(e);
+ for (Throwable error : causalChain) {
+ if (error instanceof NetconfDocumentedException) {
+ throw new RestconfDocumentedException(error.getMessage(),
+ RestconfError.ErrorType.valueOfCaseInsensitive(
+ ((NetconfDocumentedException) error).getErrorType().getTypeValue()),
+ RestconfError.ErrorTag.valueOfCaseInsensitive(
+ ((NetconfDocumentedException) error).getErrorTag().getTagValue()), e);
+ }
+ }
+
+ throw new RestconfDocumentedException("Transaction(" + txType + ") not committed correctly", e);
} else {
- throw new RestconfDocumentedException(
- "Transaction(" + txType + ") not committed correctly", e);
+ throw new RestconfDocumentedException("Transaction failed", e);
}
}
}
<type>pom</type>
<scope>import</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-artifacts</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.netconf</groupId>
<artifactId>restconf-artifacts</artifactId>