use of org.opendaylight.restconf.common.patch.PatchEntity in project netconf by opendaylight.
the class JsonPatchBodyReader method readFrom.
private PatchContext readFrom(final InstanceIdentifierContext<?> path, final InputStream entityStream) throws IOException {
final JsonReader jsonReader = new JsonReader(new InputStreamReader(entityStream, StandardCharsets.UTF_8));
AtomicReference<String> patchId = new AtomicReference<>();
final List<PatchEntity> resultList = read(jsonReader, path, patchId);
jsonReader.close();
return new PatchContext(path, resultList, patchId.get());
}
use of org.opendaylight.restconf.common.patch.PatchEntity in project netconf by opendaylight.
the class XmlToPatchBodyReader method parse.
private static PatchContext parse(final InstanceIdentifierContext<?> pathContext, final Document doc) throws XMLStreamException, IOException, ParserConfigurationException, SAXException, URISyntaxException {
final List<PatchEntity> resultCollection = new ArrayList<>();
final String patchId = doc.getElementsByTagName("patch-id").item(0).getFirstChild().getNodeValue();
final NodeList editNodes = doc.getElementsByTagName("edit");
for (int i = 0; i < editNodes.getLength(); i++) {
DataSchemaNode schemaNode = (DataSchemaNode) pathContext.getSchemaNode();
final Element element = (Element) editNodes.item(i);
final String operation = element.getElementsByTagName("operation").item(0).getFirstChild().getNodeValue();
final PatchEditOperation oper = PatchEditOperation.valueOf(operation.toUpperCase(Locale.ROOT));
final String editId = element.getElementsByTagName("edit-id").item(0).getFirstChild().getNodeValue();
final String target = element.getElementsByTagName("target").item(0).getFirstChild().getNodeValue();
final List<Element> values = readValueNodes(element, oper);
final Element firstValueElement = values != null ? values.get(0) : null;
// get namespace according to schema node from path context or value
final String namespace = firstValueElement == null ? schemaNode.getQName().getNamespace().toString() : firstValueElement.getNamespaceURI();
// find module according to namespace
final Module module = pathContext.getSchemaContext().findModules(XMLNamespace.of(namespace)).iterator().next();
// initialize codec + set default prefix derived from module name
final StringModuleInstanceIdentifierCodec codec = new StringModuleInstanceIdentifierCodec(pathContext.getSchemaContext(), module.getName());
// find complete path to target and target schema node
// target can be also empty (only slash)
YangInstanceIdentifier targetII;
final SchemaNode targetNode;
final Inference inference;
if (target.equals("/")) {
targetII = pathContext.getInstanceIdentifier();
targetNode = pathContext.getSchemaContext();
inference = Inference.ofDataTreePath(pathContext.getSchemaContext(), schemaNode.getQName());
} else {
targetII = codec.deserialize(codec.serialize(pathContext.getInstanceIdentifier()).concat(prepareNonCondXpath(schemaNode, target.replaceFirst("/", ""), firstValueElement, namespace, module.getQNameModule().getRevision().map(Revision::toString).orElse(null))));
// move schema node
schemaNode = verifyNotNull(codec.getDataContextTree().findChild(targetII).orElseThrow().getDataSchemaNode());
final SchemaInferenceStack stack = SchemaInferenceStack.of(pathContext.getSchemaContext());
targetII.getPathArguments().stream().filter(arg -> !(arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates)).filter(arg -> !(arg instanceof YangInstanceIdentifier.AugmentationIdentifier)).forEach(p -> stack.enterSchemaTree(p.getNodeType()));
final EffectiveStatement<?, ?> parentStmt = stack.exit();
verify(parentStmt instanceof SchemaNode, "Unexpected parent %s", parentStmt);
targetNode = (SchemaNode) parentStmt;
inference = stack.toInference();
}
if (targetNode == null) {
LOG.debug("Target node {} not found in path {} ", target, pathContext.getSchemaNode());
throw new RestconfDocumentedException("Error parsing input", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
if (oper.isWithValue()) {
final NormalizedNode parsed;
if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) {
final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
final XmlParserStream xmlParser = XmlParserStream.create(writer, inference);
xmlParser.traverse(new DOMSource(firstValueElement));
parsed = resultHolder.getResult();
} else {
parsed = null;
}
// for lists allow to manipulate with list items through their parent
if (targetII.getLastPathArgument() instanceof NodeIdentifierWithPredicates) {
targetII = targetII.getParent();
}
resultCollection.add(new PatchEntity(editId, oper, targetII, parsed));
} else {
resultCollection.add(new PatchEntity(editId, oper, targetII));
}
}
return new PatchContext(pathContext, ImmutableList.copyOf(resultCollection), patchId);
}
use of org.opendaylight.restconf.common.patch.PatchEntity in project netconf by opendaylight.
the class BrokerFacade method patchConfigurationDataWithinTransaction.
public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext) throws Exception {
final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
// get new transaction and schema context on server or on mounted device
final EffectiveModelContext schemaContext;
final DOMDataTreeReadWriteTransaction patchTransaction;
if (mountPoint == null) {
schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
patchTransaction = this.domDataBroker.newReadWriteTransaction();
} else {
schemaContext = modelContext(mountPoint);
final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
if (optional.isPresent()) {
patchTransaction = optional.get().newReadWriteTransaction();
} else {
// if mount point does not have broker it is not possible to continue and global error is reported
LOG.error("Http Patch {} has failed - device {} does not support broker service", patchContext.getPatchId(), mountPoint.getIdentifier());
return new PatchStatusContext(patchContext.getPatchId(), null, false, ImmutableList.of(new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "DOM data broker service isn't available for mount point " + mountPoint.getIdentifier())));
}
}
final List<PatchStatusEntity> editCollection = new ArrayList<>();
List<RestconfError> editErrors;
boolean withoutError = true;
for (final PatchEntity patchEntity : patchContext.getData()) {
final PatchEditOperation operation = patchEntity.getOperation();
switch(operation) {
case CREATE:
if (withoutError) {
try {
postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(), patchEntity.getNode(), schemaContext);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
LOG.error("Error call http Patch operation {} on target {}", operation, patchEntity.getTargetNode().toString());
editErrors = new ArrayList<>();
editErrors.addAll(e.getErrors());
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
withoutError = false;
}
}
break;
case REPLACE:
if (withoutError) {
try {
putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(), patchEntity.getNode(), schemaContext);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
LOG.error("Error call http Patch operation {} on target {}", operation, patchEntity.getTargetNode().toString());
editErrors = new ArrayList<>();
editErrors.addAll(e.getErrors());
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
withoutError = false;
}
}
break;
case DELETE:
case REMOVE:
if (withoutError) {
try {
deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode());
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
LOG.error("Error call http Patch operation {} on target {}", operation, patchEntity.getTargetNode().toString());
editErrors = new ArrayList<>();
editErrors.addAll(e.getErrors());
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
withoutError = false;
}
}
break;
case MERGE:
if (withoutError) {
try {
mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(), patchEntity.getNode(), schemaContext);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
LOG.error("Error call http Patch operation {} on target {}", operation, patchEntity.getTargetNode().toString());
editErrors = new ArrayList<>();
editErrors.addAll(e.getErrors());
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
withoutError = false;
}
}
break;
default:
LOG.error("Unsupported http Patch operation {} on target {}", operation, patchEntity.getTargetNode().toString());
break;
}
}
// if errors then cancel transaction and return error status
if (!withoutError) {
patchTransaction.cancel();
return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
}
// if no errors commit transaction
final CountDownLatch waiter = new CountDownLatch(1);
final FluentFuture<? extends CommitInfo> future = patchTransaction.commit();
final PatchStatusContextHelper status = new PatchStatusContextHelper();
future.addCallback(new FutureCallback<CommitInfo>() {
@Override
public void onSuccess(final CommitInfo result) {
status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), true, null));
waiter.countDown();
}
@Override
public void onFailure(final Throwable throwable) {
// if commit failed it is global error
LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, ImmutableList.of(new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
waiter.countDown();
}
}, MoreExecutors.directExecutor());
waiter.await();
return status.getStatus();
}
use of org.opendaylight.restconf.common.patch.PatchEntity in project netconf by opendaylight.
the class PatchDataTransactionUtilTest method testPatchDataCreateAndDelete.
@Test
public void testPatchDataCreateAndDelete() {
doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.instanceIdContainer);
doReturn(immediateTrueFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).create(LogicalDatastoreType.CONFIGURATION, this.instanceIdContainer, this.buildBaseContainerForTests, Optional.empty());
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).delete(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
final PatchEntity entityCreate = new PatchEntity("edit1", CREATE, this.instanceIdContainer, this.buildBaseContainerForTests);
final PatchEntity entityDelete = new PatchEntity("edit2", DELETE, this.targetNodeForCreateAndDelete);
final List<PatchEntity> entities = new ArrayList<>();
entities.add(entityCreate);
entities.add(entityDelete);
final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchCD");
patch(patchContext, new MdsalRestconfStrategy(mockDataBroker), true);
patch(patchContext, new NetconfRestconfStrategy(netconfService), true);
}
use of org.opendaylight.restconf.common.patch.PatchEntity in project netconf by opendaylight.
the class PatchDataTransactionUtilTest method deleteNonexistentDataTest.
@Test
public void deleteNonexistentDataTest() {
doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
final NetconfDocumentedException exception = new NetconfDocumentedException("id", ErrorType.RPC, ErrorTag.DATA_MISSING, ErrorSeverity.ERROR);
final SettableFuture<? extends DOMRpcResult> ret = SettableFuture.create();
ret.setException(new TransactionCommitFailedException(String.format("Commit of transaction %s failed", this), exception));
doReturn(ret).when(this.netconfService).commit();
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).delete(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
final PatchEntity entityDelete = new PatchEntity("edit", DELETE, this.targetNodeForCreateAndDelete);
final List<PatchEntity> entities = new ArrayList<>();
entities.add(entityDelete);
final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchD");
deleteMdsal(patchContext, new MdsalRestconfStrategy(mockDataBroker));
deleteNetconf(patchContext, new NetconfRestconfStrategy(netconfService));
}
Aggregations