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