a4452b6e986b6951cfb3af25092967cf6c5bd5e6
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / TransactionUtil.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
9 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
18 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
20 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
21 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
22 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
23 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
24 import org.opendaylight.restconf.nb.rfc8040.RestConnectorProvider;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
27 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
28 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * Util class for common methods of transactions.
35  *
36  */
37 public final class TransactionUtil {
38
39     private static final Logger LOG = LoggerFactory.getLogger(TransactionUtil.class);
40
41     private TransactionUtil() {
42         throw new UnsupportedOperationException("Util class");
43     }
44
45     /**
46      * Merged parents of data.
47      *
48      * @param path
49      *             path of data
50      * @param schemaContext
51      *             {@link SchemaContext}
52      * @param writeTx
53      *             write transaction
54      */
55     public static void ensureParentsByMerge(final YangInstanceIdentifier path, final SchemaContext schemaContext,
56             final DOMDataWriteTransaction writeTx) {
57         final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
58         YangInstanceIdentifier rootNormalizedPath = null;
59
60         final Iterator<PathArgument> it = path.getPathArguments().iterator();
61
62         while (it.hasNext()) {
63             final PathArgument pathArgument = it.next();
64             if (rootNormalizedPath == null) {
65                 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
66             }
67
68             if (it.hasNext()) {
69                 normalizedPathWithoutChildArgs.add(pathArgument);
70             }
71         }
72
73         if (normalizedPathWithoutChildArgs.isEmpty()) {
74             return;
75         }
76
77         Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
78
79         final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
80                 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
81         writeTx.merge(LogicalDatastoreType.CONFIGURATION, rootNormalizedPath, parentStructure);
82     }
83
84     /**
85      * Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
86      * data does NOT already exists.
87      * @param transactionChain Transaction chain
88      * @param rwTransaction Transaction
89      * @param store Datastore
90      * @param path Path to be checked
91      * @param operationType Type of operation (READ, POST, PUT, DELETE...)
92      */
93     public static void checkItemExists(final DOMTransactionChain transactionChain,
94                                        final DOMDataReadWriteTransaction rwTransaction,
95                                        final LogicalDatastoreType store, final YangInstanceIdentifier path,
96                                        final String operationType) {
97         final CheckedFuture<Boolean, ReadFailedException> future = rwTransaction.exists(store, path);
98         final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
99
100         FutureCallbackTx.addCallback(future, operationType, response);
101
102         if (!response.result) {
103             // close transaction and reset transaction chain
104             rwTransaction.cancel();
105             RestConnectorProvider.resetTransactionChainForAdapaters(transactionChain);
106
107             // throw error
108             final String errMsg = "Operation via Restconf was not executed because data does not exist";
109             LOG.trace("{}:{}", errMsg, path);
110             throw new RestconfDocumentedException(
111                     "Data does not exist", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, path);
112         }
113     }
114
115     /**
116      * Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
117      * data already exists.
118      * @param transactionChain Transaction chain
119      * @param rwTransaction Transaction
120      * @param store Datastore
121      * @param path Path to be checked
122      * @param operationType Type of operation (READ, POST, PUT, DELETE...)
123      */
124     public static void checkItemDoesNotExists(final DOMTransactionChain transactionChain,
125                                               final DOMDataReadWriteTransaction rwTransaction,
126                                               final LogicalDatastoreType store, final YangInstanceIdentifier path,
127                                               final String operationType) {
128         final CheckedFuture<Boolean, ReadFailedException> future = rwTransaction.exists(store, path);
129         final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
130
131         FutureCallbackTx.addCallback(future, operationType, response);
132
133         if (response.result) {
134             // close transaction and reset transaction chain
135             rwTransaction.cancel();
136             RestConnectorProvider.resetTransactionChainForAdapaters(transactionChain);
137
138             // throw error
139             final String errMsg = "Operation via Restconf was not executed because data already exists";
140             LOG.trace("{}:{}", errMsg, path);
141             throw new RestconfDocumentedException(
142                     "Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, path);
143         }
144     }
145 }