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