io.lighty.codecs.util.ConverterUtils Maven / Gradle / Ivy
/*
* Copyright (c) 2021 PANTHEON.tech s.r.o. All Rights Reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at https://www.eclipse.org/legal/epl-v10.html
*/
package io.lighty.codecs.util;
import com.google.common.base.Strings;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.netconf.api.DocumentedException;
import org.opendaylight.netconf.api.xml.XmlElement;
import org.opendaylight.netconf.api.xml.XmlUtil;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.util.DataSchemaContext;
import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
* A utility class which may be helpful while manipulating with binding independent nodes.
*/
public final class ConverterUtils {
private ConverterUtils() {
throw new UnsupportedOperationException("Do not create an instance of utility class");
}
/**
* Returns the {@link RpcDefinition} from the given {@link EffectiveModelContext} and given {@link QName}.
* The {@link QName} of a rpc can be constructed via
*
*
* {@code
* QName.create("http://netconfcentral.org/ns/toaster", "2009-11-20", "make-toast");
* } , where {@code "make-toast"} is the name of the RPC given in the yang model.
*
*
* If the given RPC was found in the {@link EffectiveModelContext} the {@link RpcDefinition} will be returned
*
* @param effectiveModelContext the effective model context used for the RPC resolution
* @param rpcQName {@link QName} of the RPC
* @return {@link Optional} representation of the {@link RpcDefinition}
* @see QName
*/
public static Optional extends RpcDefinition> loadRpc(final EffectiveModelContext effectiveModelContext,
final QName rpcQName) {
Optional findModule = findModule(effectiveModelContext, rpcQName);
if (findModule.isEmpty()) {
return Optional.empty();
}
return findDefinition(rpcQName, findModule.get().getRpcs());
}
/**
* Utility method to extract the {@link SchemaNode} for the given Notification.
*
* @param effectiveModelContext to be used
* @param notificationQname yang RPC name
* @return {@link Optional} of {@link SchemaNode}
*/
public static Optional extends NotificationDefinition> loadNotification(
final EffectiveModelContext effectiveModelContext, final QName notificationQname) {
Optional findModule = findModule(effectiveModelContext, notificationQname);
if (!findModule.isPresent()) {
return Optional.empty();
}
return findDefinition(notificationQname, findModule.get().getNotifications());
}
/**
* This method extracts from the given {@link XmlElement} the name and namespace from the first
* element and creates a {@link QName}.
*
* @param xmlElement input data.
* @return {@link QName} for input data or empty.
*/
public static Optional getRpcQName(final XmlElement xmlElement) {
String nxmlNamespace = xmlElement.namespace();
String name = xmlElement.getName();
if (Strings.isNullOrEmpty(name)) {
return Optional.empty();
}
String revision = null;
String namespace;
if (nxmlNamespace != null) {
String[] split = nxmlNamespace.split("\\?");
if (split.length > 1 && split[1].contains("revision=")) {
revision = split[1].replace("revision=", "");
}
namespace = split[0];
} else {
return Optional.of(QName.create(name));
}
if (Strings.isNullOrEmpty(revision)) {
return Optional.of(QName.create(namespace, name));
} else {
return Optional.of(QName.create(namespace, revision, name));
}
}
/**
* Create RPC QName.
*
* @param inputString RPC name
* @return {@link QName} for RPC name or empty.
* @throws IllegalArgumentException if there was a problem during parsing the XML document
* @see ConverterUtils#getRpcQName(XmlElement)
*/
public static Optional getRpcQName(final String inputString) {
try {
return getRpcQName(XmlElement.fromString(inputString));
} catch (DocumentedException e) {
throw new IllegalArgumentException(e);
}
}
public static XmlElement rpcAsInput(final XmlElement inputXmlElement) {
return rpcAsInput(inputXmlElement, "");
}
/**
* Removes the first XML tag and replaces it with an {@code } element. This method may be
* useful when converting the input of a rpc. The provided namespace will be used for the input tag
* document.
*
* @param inputXmlElement input xml data to wrap.
* @param namespace namespace
* @return wrapped xml data.
*/
public static XmlElement rpcAsInput(final XmlElement inputXmlElement, final String namespace) {
return wrapNodes("input", namespace, inputXmlElement.getChildElements());
}
/**
* Calls the method {@link ConverterUtils#rpcAsOutput(XmlElement, String)} with an empty namespace.
*
* @param inputXmlElement input rpc element data.
* @return wrapped xml element.
* @see ConverterUtils#rpcAsOutput(XmlElement, String)
* @see XmlUtil
*/
public static XmlElement rpcAsOutput(final XmlElement inputXmlElement) {
return rpcAsOutput(inputXmlElement, "");
}
/**
* Removes the first XML tag and replaces it with an {@code