Reorganize transactionChainHandler usage.
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / FutureCallbackTx.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
9
10 import com.google.common.base.Throwables;
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
17 import org.opendaylight.mdsal.dom.api.DOMActionException;
18 import org.opendaylight.mdsal.dom.api.DOMRpcException;
19 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
20 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
21 import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
22 import org.opendaylight.netconf.api.NetconfDocumentedException;
23 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
24 import org.opendaylight.restconf.common.errors.RestconfError;
25 import org.opendaylight.yangtools.yang.common.RpcError;
26 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Add callback for future objects and result set to the data factory.
32  */
33 final class FutureCallbackTx {
34
35     private static final Logger LOG = LoggerFactory.getLogger(FutureCallbackTx.class);
36
37     private FutureCallbackTx() {
38         throw new UnsupportedOperationException("Util class");
39     }
40
41     /**
42      * Add callback to the future object.
43      *
44      * @param listenableFuture
45      *             future object
46      * @param txType
47      *             type of operation (READ, POST, PUT, DELETE)
48      * @param dataFactory
49      *             factory setting result
50      * @throws RestconfDocumentedException
51      *             if the Future throws an exception
52      */
53     @SuppressWarnings("checkstyle:IllegalCatch")
54     static <T> void addCallback(final ListenableFuture<T> listenableFuture, final String txType,
55                                 final FutureDataFactory<? super T> dataFactory) throws RestconfDocumentedException {
56         addCallback(listenableFuture,txType,dataFactory,null);
57     }
58
59     /**
60      * Add callback to the future object and close transaction chain.
61      *
62      * @param listenableFuture
63      *             future object
64      * @param txType
65      *             type of operation (READ, POST, PUT, DELETE)
66      * @param dataFactory
67      *             factory setting result
68      * @param transactionChain
69      *             transaction chain
70      * @throws RestconfDocumentedException
71      *             if the Future throws an exception
72      */
73     @SuppressWarnings("checkstyle:IllegalCatch")
74     static <T> void addCallback(final ListenableFuture<T> listenableFuture, final String txType,
75             final FutureDataFactory<? super T> dataFactory, @Nullable final DOMTransactionChain transactionChain)
76             throws RestconfDocumentedException {
77
78         try {
79             final T result = listenableFuture.get();
80             dataFactory.setResult(result);
81             LOG.trace("Transaction({}) SUCCESSFUL", txType);
82         } catch (InterruptedException e) {
83             dataFactory.setFailureStatus();
84             LOG.warn("Transaction({}) FAILED!", txType, e);
85             throw new RestconfDocumentedException("Transaction failed", e);
86         } catch (ExecutionException e) {
87             dataFactory.setFailureStatus();
88             LOG.warn("Transaction({}) FAILED!", txType, e);
89
90             final Throwable cause = e.getCause();
91             if (cause instanceof DOMRpcException) {
92                 dataFactory.setResult((T) new DefaultDOMRpcResult(ImmutableList.of(
93                     RpcResultBuilder.newError(RpcError.ErrorType.RPC, "operation-failed", cause.getMessage()))));
94             } else if (cause instanceof DOMActionException) {
95                 dataFactory.setResult((T) new SimpleDOMActionResult(ImmutableList.of(
96                     RpcResultBuilder.newError(RpcError.ErrorType.RPC, "operation-failed", cause.getMessage()))));
97             } else if (cause instanceof TransactionCommitFailedException) {
98                 /* If device send some error message we want this message to get to client
99                    and not just to throw it away or override it with new generic message.
100                    We search for NetconfDocumentedException that was send from netconfSB
101                    and we create RestconfDocumentedException accordingly.
102                 */
103                 final List<Throwable> causalChain = Throwables.getCausalChain(cause);
104                 for (Throwable error : causalChain) {
105                     if (error instanceof NetconfDocumentedException) {
106                         throw new RestconfDocumentedException(error.getMessage(),
107                                 RestconfError.ErrorType.valueOfCaseInsensitive(
108                                         ((NetconfDocumentedException) error).getErrorType().getTypeValue()),
109                                 RestconfError.ErrorTag.valueOfCaseInsensitive(
110                                         ((NetconfDocumentedException) error).getErrorTag().getTagValue()), e);
111                     }
112                 }
113
114                 throw new RestconfDocumentedException("Transaction(" + txType + ") not committed correctly", e);
115             } else {
116                 throw new RestconfDocumentedException("Transaction failed", e);
117             }
118         } finally {
119             if (transactionChain != null) {
120                 transactionChain.close();
121             }
122         }
123     }
124 }