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