2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
10 import com.google.common.collect.ImmutableList;
11 import com.google.common.collect.Lists;
12 import com.google.common.util.concurrent.FluentFuture;
13 import java.util.ArrayList;
14 import java.util.List;
15 import javax.ws.rs.core.Response.Status;
16 import org.opendaylight.mdsal.common.api.CommitInfo;
17 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
18 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
19 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
20 import org.opendaylight.restconf.common.errors.RestconfError;
21 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
22 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
23 import org.opendaylight.restconf.common.patch.PatchContext;
24 import org.opendaylight.restconf.common.patch.PatchEntity;
25 import org.opendaylight.restconf.common.patch.PatchStatusContext;
26 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
27 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 public final class PatchDataTransactionUtil {
35 private static final Logger LOG = LoggerFactory.getLogger(PatchDataTransactionUtil.class);
36 // FIXME: why is this used from other contexts?
37 static final String PATCH_TX_TYPE = "Patch";
39 private PatchDataTransactionUtil() {
40 throw new UnsupportedOperationException("Util class.");
44 * Process edit operations of one {@link PatchContext}. Close {@link DOMTransactionChain} if any inside of object
45 * {@link RestconfStrategy} provided as a parameter.
47 * @param context Patch context to be processed
48 * @param strategy object that perform the actual DS operations
49 * @param schemaContext Global schema context
50 * @return {@link PatchStatusContext}
52 public static PatchStatusContext patchData(final PatchContext context, final RestconfStrategy strategy,
53 final EffectiveModelContext schemaContext) {
54 final List<PatchStatusEntity> editCollection = new ArrayList<>();
55 boolean noError = true;
56 strategy.prepareReadWriteExecution();
58 for (final PatchEntity patchEntity : context.getData()) {
60 switch (patchEntity.getOperation()) {
63 createDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
64 schemaContext, strategy);
65 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
66 } catch (final RestconfDocumentedException e) {
67 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
68 false, Lists.newArrayList(e.getErrors())));
74 deleteDataWithinTransaction(patchEntity.getTargetNode(), strategy);
75 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
76 } catch (final RestconfDocumentedException e) {
77 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
78 false, Lists.newArrayList(e.getErrors())));
84 mergeDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
85 schemaContext, strategy);
86 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
87 } catch (final RestconfDocumentedException e) {
88 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
89 false, Lists.newArrayList(e.getErrors())));
95 replaceDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
96 schemaContext, strategy);
97 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
98 } catch (final RestconfDocumentedException e) {
99 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
100 false, Lists.newArrayList(e.getErrors())));
106 removeDataWithinTransaction(patchEntity.getTargetNode(), strategy);
107 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
108 } catch (final RestconfDocumentedException e) {
109 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
110 false, Lists.newArrayList(e.getErrors())));
115 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
116 false, Lists.newArrayList(new RestconfError(ErrorType.PROTOCOL,
117 ErrorTag.OPERATION_NOT_SUPPORTED, "Not supported Yang Patch operation"))));
126 // if no errors then submit transaction, otherwise cancel
128 final ResponseFactory response = new ResponseFactory(Status.OK);
129 final FluentFuture<? extends CommitInfo> future = strategy.commit();
132 //This method will close transactionChain if any
133 FutureCallbackTx.addCallback(future, PATCH_TX_TYPE, response, strategy.getTransactionChain());
134 } catch (final RestconfDocumentedException e) {
135 // if errors occurred during transaction commit then patch failed and global errors are reported
136 return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false,
137 Lists.newArrayList(e.getErrors()));
140 return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), true, null);
143 return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
148 * Create data within one transaction, return error if already exists.
150 * @param path Path for data to be created
151 * @param payload Data to be created
152 * @param strategy Object that perform the actual DS operations
154 private static void createDataWithinTransaction(final YangInstanceIdentifier path,
155 final NormalizedNode<?, ?> payload,
156 final EffectiveModelContext schemaContext,
157 final RestconfStrategy strategy) {
158 LOG.trace("POST {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
160 createData(payload, path, strategy, schemaContext, true);
164 * Remove data within one transaction.
166 * @param path Path for data to be deleted
167 * @param strategy Object that perform the actual DS operations
169 private static void deleteDataWithinTransaction(final YangInstanceIdentifier path,
170 final RestconfStrategy strategy) {
171 LOG.trace("Delete {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
172 strategy.delete(LogicalDatastoreType.CONFIGURATION, path);
176 * Merge data within one transaction.
178 * @param path Path for data to be merged
179 * @param payload Data to be merged
180 * @param strategy Object that perform the actual DS operations
182 private static void mergeDataWithinTransaction(final YangInstanceIdentifier path,
183 final NormalizedNode<?, ?> payload,
184 final EffectiveModelContext schemaContext,
185 final RestconfStrategy strategy) {
186 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
188 TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
189 strategy.merge(LogicalDatastoreType.CONFIGURATION, path, payload);
193 * Do NOT check if data exists and remove it within one transaction.
195 * @param path Path for data to be deleted
196 * @param strategy Object that perform the actual DS operations
198 private static void removeDataWithinTransaction(final YangInstanceIdentifier path,
199 final RestconfStrategy strategy) {
200 LOG.trace("Remove {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
201 strategy.remove(LogicalDatastoreType.CONFIGURATION, path);
205 * Create data within one transaction, replace if already exists.
207 * @param path Path for data to be created
208 * @param payload Data to be created
209 * @param strategy Object that perform the actual DS operations
211 private static void replaceDataWithinTransaction(final YangInstanceIdentifier path,
212 final NormalizedNode<?, ?> payload,
213 final EffectiveModelContext schemaContext,
214 final RestconfStrategy strategy) {
215 LOG.trace("PUT {} within Restconf Patch: {} with payload {}",
216 LogicalDatastoreType.CONFIGURATION.name(), path, payload);
217 createData(payload, path, strategy, schemaContext, false);
221 * Create data within one transaction. If {@code errorIfExists} is set to {@code true} then data will be checked
222 * for existence before created, otherwise they will be overwritten.
224 * @param data Data to be created
225 * @param path Path for data to be created
226 * @param strategy Object that perform the actual DS operations
227 * @param errorIfExists Enable checking for existence of data (throws error if already exists)
229 private static void createData(final NormalizedNode<?, ?> data,
230 final YangInstanceIdentifier path,
231 final RestconfStrategy strategy,
232 final EffectiveModelContext schemaContext,
233 final boolean errorIfExists) {
235 strategy.create(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
237 strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);