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