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