import com.google.common.base.Optional;
import java.io.IOException;
+import java.util.Map;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
return result;
}
- private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) {
+ private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) throws NetconfDocumentedException {
for (XmlElement srcChild : src.getChildElements()) {
for (XmlElement filterChild : filter.getChildElements()) {
addSubtree2(filterChild, srcChild, dst);
}
}
- private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) {
+ private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) throws NetconfDocumentedException {
Document document = dstParent.getDomElement().getOwnerDocument();
MatchingResult matches = matches(src, filter);
if (matches != MatchingResult.NO_MATCH && matches != MatchingResult.CONTENT_MISMATCH) {
* Shallow compare src node to filter: tag name and namespace must match.
* If filter node has no children and has text content, it also must match.
*/
- private static MatchingResult matches(XmlElement src, XmlElement filter) {
+ private static MatchingResult matches(XmlElement src, XmlElement filter) throws NetconfDocumentedException {
boolean tagMatch = src.getName().equals(filter.getName()) &&
src.getNamespaceOptionally().equals(filter.getNamespaceOptionally());
MatchingResult result = null;
// match text content
Optional<String> maybeText = filter.getOnlyTextContentOptionally();
if (maybeText.isPresent()) {
- if (maybeText.equals(src.getOnlyTextContentOptionally())) {
+ if (maybeText.equals(src.getOnlyTextContentOptionally()) || prefixedContentMatches(filter, src)) {
result = MatchingResult.CONTENT_MATCH;
} else {
result = MatchingResult.CONTENT_MISMATCH;
if (result == null) {
result = MatchingResult.NO_MATCH;
}
- logger.debug("Matching {} to {} resulted in {}", src, filter, tagMatch);
+ logger.debug("Matching {} to {} resulted in {}", src, filter, result);
return result;
}
+ private static boolean prefixedContentMatches(final XmlElement filter, final XmlElement src) throws NetconfDocumentedException {
+ final Map.Entry<String, String> prefixToNamespaceOfFilter = filter.findNamespaceOfTextContent();
+ final Map.Entry<String, String> prefixToNamespaceOfSrc = src.findNamespaceOfTextContent();
+
+ final String prefix = prefixToNamespaceOfFilter.getKey();
+ // If this is not a prefixed content, we do not need to continue since content do not match
+ if(prefix.equals(XmlElement.DEFAULT_NAMESPACE_PREFIX)) {
+ return false;
+ }
+ // Namespace mismatch
+ if(!prefixToNamespaceOfFilter.getValue().equals(prefixToNamespaceOfSrc.getValue())) {
+ return false;
+ }
+
+ final String unprefixedFilterContent = filter.getTextContent().substring(prefix.length());
+ final String unprefixedSrcCOntnet = src.getTextContent().substring(prefix.length());
+ // Finally compare unprefixed content
+ return unprefixedFilterContent.equals(unprefixedSrcCOntnet);
+ }
+
enum MatchingResult {
NO_MATCH, TAG_MATCH, CONTENT_MATCH, CONTENT_MISMATCH
}
@Parameters
public static Collection<Object[]> data() {
List<Object[]> result = new ArrayList<>();
- for (int i = 0; i <= 8; i++) {
+ for (int i = 0; i <= 9; i++) {
result.add(new Object[]{i});
}
return result;
--- /dev/null
+<rpc-reply message-id="5"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <data>
+ <top xmlns="http://example.com/schema/1.2/config">
+ <users>
+ <user>
+ <name>fred</name>
+ <type xmlns:x="http://java.sun.com/dtd/properties.dtd">x:admin</type>
+ <full-name>Fred Flintstone</full-name>
+ </user>
+ </users>
+ </top>
+ </data>
+</rpc-reply>
\ No newline at end of file
--- /dev/null
+<rpc-reply message-id="5" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <data>
+ <top xmlns="http://example.com/schema/1.2/config">
+ <users>
+ <user>
+ <name>root</name>
+ <type>superuser</type>
+ <full-name>Charlie Root</full-name>
+ <company-info>
+ <dept>1</dept>
+ <id>1</id>
+ </company-info>
+ </user>
+ <user>
+ <name>fred</name>
+ <type xmlns:x="http://java.sun.com/dtd/properties.dtd">x:admin</type>
+ <full-name>Fred Flintstone</full-name>
+ <company-info>
+ <dept>2</dept>
+ <id>2</id>
+ </company-info>
+ </user>
+ <user>
+ <name>barney</name>
+ <type>admin</type>
+ <full-name>Barney Rubble</full-name>
+ <company-info>
+ <dept>2</dept>
+ <id>3</id>
+ </company-info>
+ </user>
+ </users>
+ <groups>
+ <group>
+ <name>admin</name>
+ </group>
+ </groups>
+ </top>
+ </data>
+</rpc-reply>
\ No newline at end of file
--- /dev/null
+<rpc message-id="5"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <get-config>
+ <source>
+ <running/>
+ </source>
+ <filter type="subtree">
+ <top xmlns="http://example.com/schema/1.2/config">
+ <users>
+ <user>
+ <name>fred</name>
+ <type xmlns:a="http://java.sun.com/dtd/properties.dtd">a:admin</type>
+ <full-name/>
+ </user>
+ </users>
+ </top>
+ </filter>
+ </get-config>
+</rpc>
\ No newline at end of file
public final class XmlElement {
+ public static final String DEFAULT_NAMESPACE_PREFIX = "";
+
private final Element element;
private static final Logger logger = LoggerFactory.getLogger(XmlElement.class);
return xmlElement;
}
- private static Map<String, String> extractNamespaces(Element typeElement) throws NetconfDocumentedException {
+ private Map<String, String> extractNamespaces() throws NetconfDocumentedException {
Map<String, String> namespaces = new HashMap<>();
- NamedNodeMap attributes = typeElement.getAttributes();
+ NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node attribute = attributes.item(i);
String attribKey = attribute.getNodeName();
if (attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
String prefix;
if (attribKey.equals(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
- prefix = "";
+ prefix = DEFAULT_NAMESPACE_PREFIX;
} else {
if (!attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY + ":")){
throw new NetconfDocumentedException("Attribute doesn't start with :",
namespaces.put(prefix, attribute.getNodeValue());
}
}
+
+ // namespace does not have to be defined on this element but inherited
+ if(!namespaces.containsKey(DEFAULT_NAMESPACE_PREFIX)) {
+ Optional<String> namespaceOptionally = getNamespaceOptionally();
+ if(namespaceOptionally.isPresent()) {
+ namespaces.put(DEFAULT_NAMESPACE_PREFIX, namespaceOptionally.get());
+ }
+ }
+
return namespaces;
}
}
public String getName() {
- if (element.getLocalName()!=null && !element.getLocalName().equals("")){
+ if (element.getLocalName()!=null && !element.getLocalName().equals(DEFAULT_NAMESPACE_PREFIX)){
return element.getLocalName();
}
return element.getTagName();
public String getTextContent() throws NetconfDocumentedException {
NodeList childNodes = element.getChildNodes();
if (childNodes.getLength() == 0) {
- return "";
+ return DEFAULT_NAMESPACE_PREFIX;
}
for(int i = 0; i < childNodes.getLength(); i++) {
Node textChild = childNodes.item(i);
public String getNamespaceAttribute() throws MissingNameSpaceException {
String attribute = element.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY);
- if (attribute == null || attribute.equals("")){
+ if (attribute == null || attribute.equals(DEFAULT_NAMESPACE_PREFIX)){
throw new MissingNameSpaceException(String.format("Element %s must specify namespace",
toString()),
NetconfDocumentedException.ErrorType.application,
* is found value will be null.
*/
public Map.Entry<String/* prefix */, String/* namespace */> findNamespaceOfTextContent() throws NetconfDocumentedException {
- Map<String, String> namespaces = extractNamespaces(element);
+ Map<String, String> namespaces = extractNamespaces();
String textContent = getTextContent();
int indexOfColon = textContent.indexOf(':');
String prefix;
if (indexOfColon > -1) {
prefix = textContent.substring(0, indexOfColon);
} else {
- prefix = "";
+ prefix = DEFAULT_NAMESPACE_PREFIX;
}
if (!namespaces.containsKey(prefix)) {
throw new IllegalArgumentException("Cannot find namespace for " + XmlUtil.toString(element) + ". Prefix from content is "