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