X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fmdsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fmdsal%2Fconnector%2Fops%2FEditConfig.java;h=a2aa0e20679473951cacd1191097f1368e76bac6;hp=09be4163df8ad8d5247fd23e64f34a5b4e0c5b16;hb=9beb3e67d845dc479afcbee4d290d7a6e3c4c1fc;hpb=3927509ec3ecfa32a51b725d2b7155d425f5b877 diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java index 09be4163df..a2aa0e2067 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java @@ -23,9 +23,10 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorT import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext; import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.opendaylight.yangtools.yang.data.api.ModifyAction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; @@ -44,13 +45,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; -public class EditConfig extends AbstractLastNetconfOperation { +public class EditConfig extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(EditConfig.class); private static final String OPERATION_NAME = "edit-config"; private static final String CONFIG_KEY = "config"; + private static final String TARGET_KEY = "target"; + private static final String DEFAULT_OPERATION_KEY = "default-operation"; + private final CurrentSchemaContext schemaContext; private final TransactionProvider transactionProvider; @@ -63,7 +68,17 @@ public class EditConfig extends AbstractLastNetconfOperation { @Override protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { - final XmlElement configElement = getConfigElement(operationElement); + final Datastore targetDatastore = extractTargetParameter(operationElement); + if (targetDatastore == Datastore.running) { + throw new NetconfDocumentedException("edit-config on running datastore is not supported", + ErrorType.protocol, + ErrorTag.operation_not_supported, + ErrorSeverity.error); + } + + final ModifyAction defaultAction = getDefaultOperation(operationElement); + + final XmlElement configElement = getElement(operationElement, CONFIG_KEY); for (XmlElement element : configElement.getChildElements()) { final String ns = element.getNamespace(); @@ -72,22 +87,19 @@ public class EditConfig extends AbstractLastNetconfOperation { final NormalizedNode storedNode = readStoredNode(LogicalDatastoreType.CONFIGURATION, ident); try { - final Optional> newNode = modifyNode(schemaNode, element, storedNode); + final Optional> newNode = modifyNode(schemaNode, element, storedNode, defaultAction); final DOMDataReadWriteTransaction rwTx = transactionProvider.getOrCreateTransaction(); if (newNode.isPresent()) { rwTx.put(LogicalDatastoreType.CONFIGURATION, ident, newNode.get()); } else { rwTx.delete(LogicalDatastoreType.CONFIGURATION, ident); } + } catch (final DataExistsException e) { + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_exists, ErrorSeverity.error); + } catch (final DataMissingException e) { + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_missing, ErrorSeverity.error); } catch (final DataModificationException e) { - if (e instanceof DataExistsException) { - throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_exists, ErrorSeverity.error); - } else if (e instanceof DataMissingException) { - throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_missing, ErrorSeverity.error); - } else { - //should never happen, since in edit-config only the 2 previous cases can happen - throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.operation_failed, ErrorSeverity.error); - } + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.operation_failed, ErrorSeverity.error); } } @@ -102,23 +114,32 @@ public class EditConfig extends AbstractLastNetconfOperation { final NormalizedNode node = readFuture.checkedGet().get(); return node; } else { - LOG.warn("Unable to read node : {} from {} datastore", path, logicalDatastoreType); + LOG.debug("Unable to read node : {} from {} datastore", path, logicalDatastoreType); } } catch (final ReadFailedException e) { //only log this since DataOperations.modify will handle throwing an exception or writing the node. - LOG.warn("Unable to read stored data: {}", path, e); + LOG.debug("Unable to read stored data: {}", path, e); } //we can return null here since DataOperations.modify handles null as input return null; } - private Optional getSchemaNodeFromNamespace(final String namespace, final XmlElement element){ + private Optional getSchemaNodeFromNamespace(final String namespace, final XmlElement element) throws NetconfDocumentedException{ Optional dataSchemaNode = Optional.absent(); try { //returns module with newest revision since findModuleByNamespace returns a set of modules and we only need the newest one final Module module = schemaContext.getCurrentContext().findModuleByNamespaceAndRevision(new URI(namespace), null); - dataSchemaNode = Optional.of(module.getDataChildByName(element.getName())); + DataSchemaNode schemaNode = module.getDataChildByName(element.getName()); + if (schemaNode != null) { + dataSchemaNode = Optional.of(module.getDataChildByName(element.getName())); + } else { + throw new NetconfDocumentedException("Unable to find node with namespace: " + namespace + "in module: " + module.toString(), + ErrorType.application, + ErrorTag.unknown_namespace, + ErrorSeverity.error); + } + } catch (URISyntaxException e) { LOG.debug("Unable to create URI for namespace : {}", namespace); } @@ -126,7 +147,7 @@ public class EditConfig extends AbstractLastNetconfOperation { return dataSchemaNode; } - private Optional> modifyNode(final DataSchemaNode schemaNode, final XmlElement element, final NormalizedNode storedNode) throws DataModificationException{ + private Optional> modifyNode(final DataSchemaNode schemaNode, final XmlElement element, final NormalizedNode storedNode, final ModifyAction defaultAction) throws DataModificationException{ if (schemaNode instanceof ContainerSchemaNode) { final ContainerNode modifiedNode = DomToNormalizedNodeParserFactory @@ -134,7 +155,7 @@ public class EditConfig extends AbstractLastNetconfOperation { .getContainerNodeParser() .parse(Collections.singletonList(element.getDomElement()), (ContainerSchemaNode) schemaNode); - final Optional oNode = DataOperations.modify((ContainerSchemaNode) schemaNode, (ContainerNode) storedNode, modifiedNode); + final Optional oNode = DataOperations.modify((ContainerSchemaNode) schemaNode, (ContainerNode) storedNode, modifiedNode, defaultAction); if (!oNode.isPresent()) { return Optional.absent(); } @@ -148,7 +169,7 @@ public class EditConfig extends AbstractLastNetconfOperation { .getMapNodeParser() .parse(Collections.singletonList(element.getDomElement()), (ListSchemaNode) schemaNode); - final Optional oNode = DataOperations.modify((ListSchemaNode) schemaNode, (MapNode) storedNode, modifiedNode); + final Optional oNode = DataOperations.modify((ListSchemaNode) schemaNode, (MapNode) storedNode, modifiedNode, defaultAction); if (!oNode.isPresent()) { return Optional.absent(); } @@ -160,23 +181,49 @@ public class EditConfig extends AbstractLastNetconfOperation { LOG.debug("DataNode from module is not ContainerSchemaNode nor ListSchemaNode, aborting.."); return Optional.absent(); } + } + private Datastore extractTargetParameter(final XmlElement operationElement) throws NetconfDocumentedException { + final NodeList elementsByTagName = operationElement.getDomElement().getElementsByTagName(TARGET_KEY); + // Direct lookup instead of using XmlElement class due to performance + if (elementsByTagName.getLength() == 0) { + throw new NetconfDocumentedException("Missing target element", ErrorType.rpc, ErrorTag.missing_attribute, ErrorSeverity.error); + } else if (elementsByTagName.getLength() > 1) { + throw new NetconfDocumentedException("Multiple target elements", ErrorType.rpc, ErrorTag.unknown_attribute, ErrorSeverity.error); + } else { + final XmlElement targetChildNode = XmlElement.fromDomElement((Element) elementsByTagName.item(0)).getOnlyChildElement(); + return Datastore.valueOf(targetChildNode.getName()); + } } - private XmlElement getConfigElement(final XmlElement operationElement) throws NetconfDocumentedException{ - final Optional configChildNode = operationElement.getOnlyChildElementOptionally(CONFIG_KEY); - if (!configChildNode.isPresent()) { - throw new NetconfDocumentedException("Can't get child element with name: " + CONFIG_KEY, - ErrorType.application, - ErrorTag.unknown_element, + private ModifyAction getDefaultOperation(final XmlElement operationElement) throws NetconfDocumentedException { + final NodeList elementsByTagName = operationElement.getDomElement().getElementsByTagName(DEFAULT_OPERATION_KEY); + if(elementsByTagName.getLength() == 0) { + return ModifyAction.MERGE; + } else if(elementsByTagName.getLength() > 1) { + throw new NetconfDocumentedException("Multiple " + DEFAULT_OPERATION_KEY + " elements", + ErrorType.rpc, ErrorTag.unknown_attribute, ErrorSeverity.error); + } else { + return ModifyAction.fromXmlValue(elementsByTagName.item(0).getTextContent()); + } + + } + + private XmlElement getElement(final XmlElement operationElement, String elementName) throws NetconfDocumentedException { + final Optional childNode = operationElement.getOnlyChildElementOptionally(elementName); + if (!childNode.isPresent()) { + throw new NetconfDocumentedException(elementName + " element is missing", + ErrorType.protocol, + ErrorTag.missing_element, ErrorSeverity.error); } - return configChildNode.get(); + return childNode.get(); } @Override protected String getOperationName() { return OPERATION_NAME; } + }