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