blob: f672e0b8f18c0bcede39db3a8a15ecf5edafdfcc [file] [log] [blame]
Jin Gan79f75372017-01-05 15:08:11 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jin Gan79f75372017-01-05 15:08:11 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
jingan7c5bf1f2017-02-09 02:58:09 -080016
Jin Gan79f75372017-01-05 15:08:11 -080017package org.onosproject.restconf.restconfmanager;
18
19import com.fasterxml.jackson.databind.node.ObjectNode;
20import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jin Gan79f75372017-01-05 15:08:11 -080021import org.glassfish.jersey.server.ChunkedOutput;
Henry Yu14af7782017-03-09 19:33:36 -050022import org.onosproject.config.DynamicConfigService;
23import org.onosproject.config.FailedException;
24import org.onosproject.config.Filter;
Yuta HIGUCHIfa105b22018-03-01 21:16:51 -080025import org.onosproject.d.config.ResourceIds;
Sean Condon13b16812018-01-25 10:31:49 +000026import org.onosproject.restconf.api.RestconfError;
Henry Yu14af7782017-03-09 19:33:36 -050027import org.onosproject.restconf.api.RestconfException;
Henry Yuc10f7fc2017-07-26 13:42:08 -040028import org.onosproject.restconf.api.RestconfRpcOutput;
Henry Yu14af7782017-03-09 19:33:36 -050029import org.onosproject.restconf.api.RestconfService;
Henry Yuc10f7fc2017-07-26 13:42:08 -040030import org.onosproject.restconf.utils.RestconfUtils;
Henry Yu14af7782017-03-09 19:33:36 -050031import org.onosproject.yang.model.DataNode;
Henry Yuc10f7fc2017-07-26 13:42:08 -040032import org.onosproject.yang.model.DefaultResourceData;
sonugupta-huaweif0af7aa2017-03-17 00:54:52 +053033import org.onosproject.yang.model.InnerNode;
34import org.onosproject.yang.model.KeyLeaf;
35import org.onosproject.yang.model.ListKey;
36import org.onosproject.yang.model.NodeKey;
Henry Yu14af7782017-03-09 19:33:36 -050037import org.onosproject.yang.model.ResourceData;
38import org.onosproject.yang.model.ResourceId;
Henry Yuc10f7fc2017-07-26 13:42:08 -040039import org.onosproject.yang.model.RpcInput;
40import org.onosproject.yang.model.RpcOutput;
sonugupta-huaweif0af7aa2017-03-17 00:54:52 +053041import org.onosproject.yang.model.SchemaId;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042import org.osgi.service.component.annotations.Activate;
43import org.osgi.service.component.annotations.Component;
44import org.osgi.service.component.annotations.Deactivate;
45import org.osgi.service.component.annotations.Reference;
46import org.osgi.service.component.annotations.ReferenceCardinality;
Jin Gan79f75372017-01-05 15:08:11 -080047import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
Sean Condon13b16812018-01-25 10:31:49 +000050import javax.ws.rs.core.Response;
Henry Yuc10f7fc2017-07-26 13:42:08 -040051import java.net.URI;
Sean Condon13b16812018-01-25 10:31:49 +000052import java.util.Arrays;
jingan7c5bf1f2017-02-09 02:58:09 -080053import java.util.List;
Henry Yuc10f7fc2017-07-26 13:42:08 -040054import java.util.Map;
Sean Condon13b16812018-01-25 10:31:49 +000055import java.util.Optional;
Henry Yuc10f7fc2017-07-26 13:42:08 -040056import java.util.concurrent.CompletableFuture;
Jin Gan79f75372017-01-05 15:08:11 -080057import java.util.concurrent.ExecutorService;
58import java.util.concurrent.Executors;
Henry Yu14af7782017-03-09 19:33:36 -050059
Sean Condon13b16812018-01-25 10:31:49 +000060import static javax.ws.rs.core.Response.Status.CONFLICT;
Jin Gan79f75372017-01-05 15:08:11 -080061import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
Henry Yu830b5dc2017-11-16 10:44:45 -050062import static org.onosproject.d.config.ResourceIds.parentOf;
jingan7c5bf1f2017-02-09 02:58:09 -080063import static org.onosproject.restconf.utils.RestconfUtils.convertDataNodeToJson;
Henry Yu14af7782017-03-09 19:33:36 -050064import static org.onosproject.restconf.utils.RestconfUtils.convertJsonToDataNode;
Henry Yuc10f7fc2017-07-26 13:42:08 -040065import static org.onosproject.restconf.utils.RestconfUtils.rmLastPathSegment;
sonugupta-huaweif0af7aa2017-03-17 00:54:52 +053066import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_NODE;
67import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
68import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_NODE;
jingan7c5bf1f2017-02-09 02:58:09 -080069
Jin Gan79f75372017-01-05 15:08:11 -080070/*
jingan7c5bf1f2017-02-09 02:58:09 -080071 * ONOS RESTCONF application. The RESTCONF Manager
72 * implements the main logic of the RESTCONF application.
Jin Gan79f75372017-01-05 15:08:11 -080073 *
74 * The design of the RESTCONF subsystem contains 2 major bundles:
jingan7c5bf1f2017-02-09 02:58:09 -080075 * This bundle module is the back-end of the server.
Jin Gan79f75372017-01-05 15:08:11 -080076 * It provides the main logic of the RESTCONF server. It interacts with
jingan7c5bf1f2017-02-09 02:58:09 -080077 * the Dynamic Config Service and yang runtime service to run operations
78 * on the YANG data objects (i.e., resource id, yang data node).
Jin Gan79f75372017-01-05 15:08:11 -080079 */
80
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081@Component(immediate = true, service = RestconfService.class)
Jin Gan79f75372017-01-05 15:08:11 -080082public class RestconfManager implements RestconfService {
83
84 private static final String RESTCONF_ROOT = "/onos/restconf";
Jin Gan79f75372017-01-05 15:08:11 -080085
86 private final int maxNumOfWorkerThreads = 5;
87
88 private final Logger log = LoggerFactory.getLogger(getClass());
89
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Henry Yu14af7782017-03-09 19:33:36 -050091 protected DynamicConfigService dynamicConfigService;
Jin Gan79f75372017-01-05 15:08:11 -080092
Jin Gan79f75372017-01-05 15:08:11 -080093 private ExecutorService workerThreadPool;
94
95 @Activate
96 protected void activate() {
97 workerThreadPool = Executors
98 .newFixedThreadPool(maxNumOfWorkerThreads,
99 new ThreadFactoryBuilder()
100 .setNameFormat("restconf-worker")
101 .build());
102 log.info("Started");
103 }
104
105 @Deactivate
106 protected void deactivate() {
Henry Yuc10f7fc2017-07-26 13:42:08 -0400107 workerThreadPool.shutdownNow();
Jin Gan79f75372017-01-05 15:08:11 -0800108 log.info("Stopped");
109 }
110
111 @Override
Henry Yuc10f7fc2017-07-26 13:42:08 -0400112 public ObjectNode runGetOperationOnDataResource(URI uri)
Jin Gan79f75372017-01-05 15:08:11 -0800113 throws RestconfException {
Henry Yu830b5dc2017-11-16 10:44:45 -0500114 DataResourceLocator rl = DataResourceLocator.newInstance(uri);
jingan7c5bf1f2017-02-09 02:58:09 -0800115 // TODO: define Filter (if there is any requirement).
Yuta HIGUCHIac85ee12017-08-03 20:07:35 -0700116 Filter filter = Filter.builder().build();
jingan7c5bf1f2017-02-09 02:58:09 -0800117 DataNode dataNode;
Henry Yuc10f7fc2017-07-26 13:42:08 -0400118
jingan7c5bf1f2017-02-09 02:58:09 -0800119 try {
Henry Yu830b5dc2017-11-16 10:44:45 -0500120 if (!dynamicConfigService.nodeExist(rl.ridForDynConfig())) {
Henry Yuc10f7fc2017-07-26 13:42:08 -0400121 return null;
122 }
Henry Yu830b5dc2017-11-16 10:44:45 -0500123 dataNode = dynamicConfigService.readNode(rl.ridForDynConfig(), filter);
jingan7c5bf1f2017-02-09 02:58:09 -0800124 } catch (FailedException e) {
125 log.error("ERROR: DynamicConfigService: ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000126 throw new RestconfException("ERROR: DynamicConfigService", e,
127 RestconfError.ErrorTag.OPERATION_FAILED, INTERNAL_SERVER_ERROR,
128 Optional.of(uri.getPath()));
jingan7c5bf1f2017-02-09 02:58:09 -0800129 }
Henry Yu830b5dc2017-11-16 10:44:45 -0500130 ObjectNode rootNode = convertDataNodeToJson(rl.ridForYangRuntime(), dataNode);
jingan7c5bf1f2017-02-09 02:58:09 -0800131 return rootNode;
Jin Gan79f75372017-01-05 15:08:11 -0800132 }
133
134 @Override
Henry Yuc10f7fc2017-07-26 13:42:08 -0400135 public void runPostOperationOnDataResource(URI uri, ObjectNode rootNode)
Jin Gan79f75372017-01-05 15:08:11 -0800136 throws RestconfException {
Henry Yu830b5dc2017-11-16 10:44:45 -0500137 DataResourceLocator rl = DataResourceLocator.newInstance(uri);
138 ResourceData receivedData = convertJsonToDataNode(rl.uriForYangRuntime(), rootNode);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400139 ResourceId rid = receivedData.resourceId();
140 List<DataNode> dataNodeList = receivedData.dataNodes();
柯志勇100686956f7ba6c2018-10-22 10:43:04 +0800141 if (dataNodeList == null || dataNodeList.isEmpty()) {
142 log.warn("There is no one Data Node can be proceed.");
143 return;
144 }
jingan7c5bf1f2017-02-09 02:58:09 -0800145 if (dataNodeList.size() > 1) {
Henry Yuc10f7fc2017-07-26 13:42:08 -0400146 log.warn("There are more than one Data Node can be proceed: {}", dataNodeList.size());
jingan7c5bf1f2017-02-09 02:58:09 -0800147 }
148 DataNode dataNode = dataNodeList.get(0);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400149
150 if (rid == null) {
151 rid = ResourceId.builder().addBranchPointSchema("/", null).build();
152 dataNode = removeTopNode(dataNode);
153 }
154
jingan7c5bf1f2017-02-09 02:58:09 -0800155 try {
Henry Yu830b5dc2017-11-16 10:44:45 -0500156 dynamicConfigService.createNode(rl.ridForDynConfig(), dataNode);
Yuta HIGUCHIfa105b22018-03-01 21:16:51 -0800157 } catch (Exception e) {
Sean Condon13b16812018-01-25 10:31:49 +0000158 if (e.getMessage().startsWith("Requested node already present")) {
159 throw new RestconfException("Already exists", e,
160 RestconfError.ErrorTag.DATA_EXISTS, CONFLICT,
161 Optional.of(uri.getPath()));
162 } else {
Yuta HIGUCHIfa105b22018-03-01 21:16:51 -0800163 log.error("ERROR: DynamicConfigService: creating {} with {}",
164 ResourceIds.toInstanceIdentifier(rl.ridForDynConfig()),
165 dataNode,
166 e);
Sean Condon13b16812018-01-25 10:31:49 +0000167 throw new RestconfException("ERROR: DynamicConfigService", e,
168 RestconfError.ErrorTag.OPERATION_FAILED, INTERNAL_SERVER_ERROR,
169 Optional.of(uri.getPath()));
170 }
jingan7c5bf1f2017-02-09 02:58:09 -0800171 }
Jin Gan79f75372017-01-05 15:08:11 -0800172 }
173
174 @Override
Henry Yuc10f7fc2017-07-26 13:42:08 -0400175 public void runPutOperationOnDataResource(URI uri, ObjectNode rootNode)
Jin Gan79f75372017-01-05 15:08:11 -0800176 throws RestconfException {
Henry Yu830b5dc2017-11-16 10:44:45 -0500177 DataResourceLocator rl = DataResourceLocator.newInstance(uri);
178 ResourceData receivedData = convertJsonToDataNode(rmLastPathSegment(rl.uriForYangRuntime()), rootNode);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400179 List<DataNode> dataNodeList = receivedData.dataNodes();
柯志勇100686956f7ba6c2018-10-22 10:43:04 +0800180 if (dataNodeList == null || dataNodeList.isEmpty()) {
181 log.warn("There is no one Data Node can be proceed.");
182 return;
183 }
Henry Yuc10f7fc2017-07-26 13:42:08 -0400184 if (dataNodeList.size() > 1) {
185 log.warn("There are more than one Data Node can be proceed: {}", dataNodeList.size());
186 }
187 DataNode dataNode = dataNodeList.get(0);
188
jingan7c5bf1f2017-02-09 02:58:09 -0800189 try {
Henry Yuc10f7fc2017-07-26 13:42:08 -0400190 /*
191 * If the data node already exists, then replace it.
192 * Otherwise, create it.
193 */
Henry Yu830b5dc2017-11-16 10:44:45 -0500194 if (dynamicConfigService.nodeExist(rl.ridForDynConfig())) {
195 dynamicConfigService.replaceNode(parentOf(rl.ridForDynConfig()), dataNode);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400196 } else {
Henry Yu830b5dc2017-11-16 10:44:45 -0500197 dynamicConfigService.createNode(parentOf(rl.ridForDynConfig()), dataNode);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400198 }
199
jingan7c5bf1f2017-02-09 02:58:09 -0800200 } catch (FailedException e) {
201 log.error("ERROR: DynamicConfigService: ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000202 throw new RestconfException("ERROR: DynamicConfigService", e,
203 RestconfError.ErrorTag.OPERATION_FAILED, INTERNAL_SERVER_ERROR,
204 Optional.of(uri.getPath()));
jingan7c5bf1f2017-02-09 02:58:09 -0800205 }
Jin Gan79f75372017-01-05 15:08:11 -0800206 }
207
208 @Override
Henry Yuc10f7fc2017-07-26 13:42:08 -0400209 public void runDeleteOperationOnDataResource(URI uri)
Jin Gan79f75372017-01-05 15:08:11 -0800210 throws RestconfException {
Henry Yu830b5dc2017-11-16 10:44:45 -0500211 DataResourceLocator rl = DataResourceLocator.newInstance(uri);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400212 try {
Henry Yu830b5dc2017-11-16 10:44:45 -0500213 if (dynamicConfigService.nodeExist(rl.ridForDynConfig())) {
214 dynamicConfigService.deleteNode(rl.ridForDynConfig());
Henry Yuc10f7fc2017-07-26 13:42:08 -0400215 }
216 } catch (FailedException e) {
217 log.error("ERROR: DynamicConfigService: ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000218 throw new RestconfException("ERROR: DynamicConfigService", e,
219 RestconfError.ErrorTag.OPERATION_FAILED, INTERNAL_SERVER_ERROR,
220 Optional.of(uri.getPath()));
Henry Yuc10f7fc2017-07-26 13:42:08 -0400221 }
222 }
223
224 @Override
225 public void runPatchOperationOnDataResource(URI uri, ObjectNode rootNode)
226 throws RestconfException {
Henry Yu830b5dc2017-11-16 10:44:45 -0500227 DataResourceLocator rl = DataResourceLocator.newInstance(uri);
228 ResourceData receivedData = convertJsonToDataNode(rmLastPathSegment(rl.uriForYangRuntime()), rootNode);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400229 ResourceId rid = receivedData.resourceId();
230 List<DataNode> dataNodeList = receivedData.dataNodes();
柯志勇10068695d34aaf22018-10-23 17:18:19 +0800231 if (dataNodeList == null || dataNodeList.isEmpty()) {
232 log.warn("There is no one Data Node can be proceed.");
233 return;
234 }
Henry Yuc10f7fc2017-07-26 13:42:08 -0400235 if (dataNodeList.size() > 1) {
236 log.warn("There are more than one Data Node can be proceed: {}", dataNodeList.size());
237 }
238 DataNode dataNode = dataNodeList.get(0);
239
240 if (rid == null) {
241 rid = ResourceId.builder().addBranchPointSchema("/", null).build();
242 dataNode = removeTopNode(dataNode);
243 }
244
245 try {
Henry Yu830b5dc2017-11-16 10:44:45 -0500246 dynamicConfigService.updateNode(parentOf(rl.ridForDynConfig()), dataNode);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400247 } catch (FailedException e) {
248 log.error("ERROR: DynamicConfigService: ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000249 throw new RestconfException("ERROR: DynamicConfigService", e,
250 RestconfError.ErrorTag.OPERATION_FAILED, INTERNAL_SERVER_ERROR,
251 Optional.of(uri.getPath()));
Henry Yuc10f7fc2017-07-26 13:42:08 -0400252 }
253 }
254
255 private DataNode removeTopNode(DataNode dataNode) {
256 if (dataNode instanceof InnerNode && dataNode.key().schemaId().name().equals("/")) {
257 Map.Entry<NodeKey, DataNode> entry = ((InnerNode) dataNode).childNodes().entrySet().iterator().next();
258 dataNode = entry.getValue();
259 }
260 return dataNode;
Jin Gan79f75372017-01-05 15:08:11 -0800261 }
262
263 @Override
264 public String getRestconfRootPath() {
265 return RESTCONF_ROOT;
266 }
267
Jin Gan79f75372017-01-05 15:08:11 -0800268 @Override
Henry Yuc10f7fc2017-07-26 13:42:08 -0400269 public void subscribeEventStream(String streamId, String clientIpAddr,
Jin Gan79f75372017-01-05 15:08:11 -0800270 ChunkedOutput<String> output)
271 throws RestconfException {
Henry Yuc10f7fc2017-07-26 13:42:08 -0400272 //TODO: to be completed
Sean Condon13b16812018-01-25 10:31:49 +0000273 throw new RestconfException("Not implemented",
274 RestconfError.ErrorTag.OPERATION_NOT_SUPPORTED,
275 Response.Status.NOT_IMPLEMENTED,
276 Optional.empty(), Optional.of("subscribeEventStream not yet implemented"));
Henry Yuc10f7fc2017-07-26 13:42:08 -0400277 }
278
279 @Override
280 public CompletableFuture<RestconfRpcOutput> runRpc(URI uri,
281 ObjectNode input,
282 String clientIpAddress) {
283 CompletableFuture<RestconfRpcOutput> result =
284 CompletableFuture.supplyAsync(() -> executeRpc(uri, input, clientIpAddress));
285 return result;
286 }
287
288 private RestconfRpcOutput executeRpc(URI uri, ObjectNode input, String clientIpAddress) {
289 ResourceData rpcInputNode = convertJsonToDataNode(uri, input);
290 ResourceId resourceId = rpcInputNode.resourceId();
291 List<DataNode> inputDataNodeList = rpcInputNode.dataNodes();
292 DataNode inputDataNode = inputDataNodeList.get(0);
Gaurav Agrawal142ceb02018-02-16 12:19:08 +0530293 RpcInput rpcInput = new RpcInput(resourceId, inputDataNode);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400294
295 RestconfRpcOutput restconfOutput = null;
296 try {
297 CompletableFuture<RpcOutput> rpcFuture =
Gaurav Agrawal142ceb02018-02-16 12:19:08 +0530298 dynamicConfigService.invokeRpc(rpcInput);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400299 RpcOutput rpcOutput = rpcFuture.get();
300 restconfOutput = RestconfUtils.convertRpcOutput(resourceId, rpcOutput);
301 } catch (InterruptedException e) {
302 log.error("ERROR: computeResultQ.take() has been interrupted.");
303 log.debug("executeRpc Exception:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000304 RestconfError error =
305 RestconfError.builder(RestconfError.ErrorType.RPC,
306 RestconfError.ErrorTag.OPERATION_FAILED)
307 .errorMessage("RPC execution has been interrupted")
308 .errorPath(uri.getPath())
309 .build();
310 restconfOutput = new RestconfRpcOutput(INTERNAL_SERVER_ERROR,
311 RestconfError.wrapErrorAsJson(Arrays.asList(error)));
Henry Yuc10f7fc2017-07-26 13:42:08 -0400312 restconfOutput.reason("RPC execution has been interrupted");
313 } catch (Exception e) {
314 log.error("ERROR: executeRpc: {}", e.getMessage());
315 log.debug("executeRpc Exception:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000316 RestconfError error =
317 RestconfError.builder(RestconfError.ErrorType.RPC,
318 RestconfError.ErrorTag.OPERATION_FAILED)
319 .errorMessage(e.getMessage())
320 .errorPath(uri.getPath())
321 .build();
322 restconfOutput = new RestconfRpcOutput(INTERNAL_SERVER_ERROR,
323 RestconfError.wrapErrorAsJson(Arrays.asList(error)));
Henry Yuc10f7fc2017-07-26 13:42:08 -0400324 restconfOutput.reason(e.getMessage());
Jin Gan79f75372017-01-05 15:08:11 -0800325 }
326
Henry Yuc10f7fc2017-07-26 13:42:08 -0400327 return restconfOutput;
Jin Gan79f75372017-01-05 15:08:11 -0800328 }
329
sonugupta-huaweif0af7aa2017-03-17 00:54:52 +0530330 private ResourceData getDataForStore(ResourceData resourceData) {
331 List<DataNode> nodes = resourceData.dataNodes();
332 ResourceId rid = resourceData.resourceId();
333 DataNode.Builder dbr = null;
334 ResourceId parentId = null;
335 try {
336 NodeKey lastKey = rid.nodeKeys().get(rid.nodeKeys().size() - 1);
337 SchemaId sid = lastKey.schemaId();
338 if (lastKey instanceof ListKey) {
339 dbr = InnerNode.builder(
340 sid.name(), sid.namespace()).type(MULTI_INSTANCE_NODE);
341 for (KeyLeaf keyLeaf : ((ListKey) lastKey).keyLeafs()) {
342 Object val = keyLeaf.leafValue();
343 dbr = dbr.addKeyLeaf(keyLeaf.leafSchema().name(),
344 sid.namespace(), val);
345 dbr = dbr.createChildBuilder(keyLeaf.leafSchema().name(),
346 sid.namespace(), val)
347 .type(SINGLE_INSTANCE_LEAF_VALUE_NODE);
sonugupta-huawei6119ac72017-03-21 16:25:40 +0530348 //Exit for key leaf node
349 dbr = dbr.exitNode();
sonugupta-huaweif0af7aa2017-03-17 00:54:52 +0530350 }
351 } else {
352 dbr = InnerNode.builder(
353 sid.name(), sid.namespace()).type(SINGLE_INSTANCE_NODE);
354 }
355 if (nodes != null && !nodes.isEmpty()) {
356 // adding the parent node for given list of nodes
357 for (DataNode node : nodes) {
358 dbr = ((InnerNode.Builder) dbr).addNode(node);
359 }
360 }
361 parentId = rid.copyBuilder().removeLastKey().build();
362 } catch (CloneNotSupportedException e) {
Ray Milkey74e59132018-01-17 15:24:52 -0800363 log.error("getDataForStore()", e);
364 return null;
sonugupta-huaweif0af7aa2017-03-17 00:54:52 +0530365 }
366 ResourceData.Builder resData = DefaultResourceData.builder();
367 resData.addDataNode(dbr.build());
368 resData.resourceId(parentId);
369 return resData.build();
370 }
Jin Gan79f75372017-01-05 15:08:11 -0800371}