Unit test for ReadDataTransactionUtil class
[netconf.git] / restconf / sal-rest-connector / src / main / java / org / opendaylight / restconf / restful / services / impl / RestconfDataServiceImpl.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.restful.services.impl;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import java.text.SimpleDateFormat;
13 import java.util.TimeZone;
14 import javax.ws.rs.core.Response;
15 import javax.ws.rs.core.UriInfo;
16 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
17 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
18 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
19 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
20 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
21 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
22 import org.opendaylight.netconf.sal.restconf.impl.PATCHContext;
23 import org.opendaylight.netconf.sal.restconf.impl.PATCHStatusContext;
24 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
25 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
26 import org.opendaylight.restconf.RestConnectorProvider;
27 import org.opendaylight.restconf.common.references.SchemaContextRef;
28 import org.opendaylight.restconf.handlers.SchemaContextHandler;
29 import org.opendaylight.restconf.handlers.TransactionChainHandler;
30 import org.opendaylight.restconf.restful.services.api.RestconfDataService;
31 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
32 import org.opendaylight.restconf.restful.utils.DeleteDataTransactionUtil;
33 import org.opendaylight.restconf.restful.utils.PatchDataTransactionUtil;
34 import org.opendaylight.restconf.restful.utils.PostDataTransactionUtil;
35 import org.opendaylight.restconf.restful.utils.PutDataTransactionUtil;
36 import org.opendaylight.restconf.restful.utils.ReadDataTransactionUtil;
37 import org.opendaylight.restconf.restful.utils.RestconfDataServiceConstant;
38 import org.opendaylight.restconf.utils.parser.ParserIdentifier;
39 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
40 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * Implementation of {@link RestconfDataService}
46  */
47 public class RestconfDataServiceImpl implements RestconfDataService {
48
49     private final static Logger LOG = LoggerFactory.getLogger(RestconfDataServiceImpl.class);
50
51     private final SchemaContextHandler schemaContextHandler;
52     private final TransactionChainHandler transactionChainHandler;
53
54     public RestconfDataServiceImpl(final SchemaContextHandler schemaContextHandler,
55             final TransactionChainHandler transactionChainHandler) {
56         this.schemaContextHandler = schemaContextHandler;
57         this.transactionChainHandler = transactionChainHandler;
58     }
59
60     @Override
61     public Response readData(final String identifier, final UriInfo uriInfo) {
62         Preconditions.checkNotNull(identifier);
63         final SchemaContextRef schemaContextRef = new SchemaContextRef(this.schemaContextHandler.get());
64
65         final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier,
66                 schemaContextRef.get());
67         final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
68         final String value = uriInfo.getQueryParameters().getFirst(RestconfDataServiceConstant.CONTENT);
69
70         DOMTransactionChain transaction = null;
71         if (mountPoint == null) {
72             transaction = this.transactionChainHandler.get();
73         } else {
74             transaction = transactionOfMountPoint(mountPoint);
75         }
76         final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(instanceIdentifier, mountPoint,
77                 transaction);
78         final NormalizedNode<?, ?> node = ReadDataTransactionUtil.readData(value, transactionNode);
79         if (node == null) {
80             throw new RestconfDocumentedException(
81                     "Request could not be completed because the relevant data model content does not exist",
82                     RestconfError.ErrorType.PROTOCOL,
83                     RestconfError.ErrorTag.DATA_MISSING);
84         }
85         final SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
86         dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
87         final String etag = '"' + node.getNodeType().getModule().getFormattedRevision()
88                 + node.getNodeType().getLocalName() + '"';
89         Response resp = null;
90         if ((value == null) || value.contains(RestconfDataServiceConstant.ReadData.CONFIG)) {
91             resp = Response.status(200).entity(new NormalizedNodeContext(instanceIdentifier, node)).header("ETag", etag)
92                     .header("Last-Modified", dateFormatGmt.toString()).build();
93         } else {
94             resp = Response.status(200).entity(new NormalizedNodeContext(instanceIdentifier, node)).build();
95         }
96         return resp;
97     }
98
99     @Override
100     public Response putData(final String identifier, final NormalizedNodeContext payload) {
101         Preconditions.checkNotNull(identifier);
102         Preconditions.checkNotNull(payload);
103
104         final InstanceIdentifierContext<? extends SchemaNode> iid = payload
105                 .getInstanceIdentifierContext();
106
107         PutDataTransactionUtil.validInputData(iid.getSchemaNode(), payload);
108         PutDataTransactionUtil.validTopLevelNodeName(iid.getInstanceIdentifier(), payload);
109         PutDataTransactionUtil.validateListKeysEqualityInPayloadAndUri(payload);
110
111         final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
112         DOMTransactionChain transaction = null;
113         SchemaContextRef ref = null;
114         if (mountPoint == null) {
115             transaction = this.transactionChainHandler.get();
116             ref = new SchemaContextRef(this.schemaContextHandler.get());
117         } else {
118             transaction = transactionOfMountPoint(mountPoint);
119             ref = new SchemaContextRef(mountPoint.getSchemaContext());
120         }
121
122         final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
123                 payload.getInstanceIdentifierContext(), mountPoint, transaction);
124         return PutDataTransactionUtil.putData(payload, ref, transactionNode);
125     }
126
127     @Override
128     public Response postData(final String identifier, final NormalizedNodeContext payload, final UriInfo uriInfo) {
129         return postData(payload, uriInfo);
130     }
131
132     @Override
133     public Response postData(final NormalizedNodeContext payload, final UriInfo uriInfo) {
134         Preconditions.checkNotNull(payload);
135
136         final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
137         DOMTransactionChain transaction = null;
138         SchemaContextRef ref = null;
139         if (mountPoint == null) {
140             transaction = this.transactionChainHandler.get();
141             ref = new SchemaContextRef(this.schemaContextHandler.get());
142         } else {
143             transaction = transactionOfMountPoint(mountPoint);
144             ref = new SchemaContextRef(mountPoint.getSchemaContext());
145         }
146         final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
147                 payload.getInstanceIdentifierContext(), mountPoint, transaction);
148         return PostDataTransactionUtil.postData(uriInfo, payload, transactionNode, ref);
149     }
150
151     @Override
152     public Response deleteData(final String identifier) {
153         final SchemaContextRef schemaContextRef = new SchemaContextRef(this.schemaContextHandler.get());
154         final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier,
155                 schemaContextRef.get());
156
157         final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
158         final DOMTransactionChain transaction;
159         if (mountPoint == null) {
160             transaction = this.transactionChainHandler.get();
161         } else {
162             transaction = transactionOfMountPoint(mountPoint);
163         }
164
165         final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(instanceIdentifier, mountPoint,
166                 transaction);
167         return DeleteDataTransactionUtil.deleteData(transactionNode);
168     }
169
170     @Override
171     public PATCHStatusContext patchData(final String identifier, final PATCHContext context, final UriInfo uriInfo) {
172         Preconditions.checkNotNull(identifier);
173         return patchData(context, uriInfo);
174     }
175
176     @Override
177     public PATCHStatusContext patchData(final PATCHContext context, final UriInfo uriInfo) {
178         Preconditions.checkNotNull(context);
179         final DOMMountPoint mountPoint = context.getInstanceIdentifierContext().getMountPoint();
180
181         final DOMTransactionChain transaction;
182         final SchemaContextRef ref;
183         if (mountPoint == null) {
184             transaction = this.transactionChainHandler.get();
185             ref = new SchemaContextRef(this.schemaContextHandler.get());
186         } else {
187             transaction = transactionOfMountPoint(mountPoint);
188             ref = new SchemaContextRef(mountPoint.getSchemaContext());
189         }
190
191         final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
192                 context.getInstanceIdentifierContext(), mountPoint, transaction);
193
194         return PatchDataTransactionUtil.patchData(context, transactionNode, ref);
195     }
196
197     /**
198      * Prepare transaction to read data of mount point, if these data are
199      * present.
200      * @param mountPoint
201      * @return {@link DOMDataReadWriteTransaction}
202      */
203     private static DOMTransactionChain transactionOfMountPoint(final DOMMountPoint mountPoint) {
204         final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
205         if (domDataBrokerService.isPresent()) {
206             return domDataBrokerService.get().createTransactionChain(RestConnectorProvider.transactionListener);
207         } else {
208             final String errMsg = "DOM data broker service isn't available for mount point "
209                     + mountPoint.getIdentifier();
210             LOG.warn(errMsg);
211             throw new RestconfDocumentedException(errMsg);
212         }
213     }
214 }