diff options
Diffstat (limited to 'plugins/restconf-client/provider/src/main')
58 files changed, 7096 insertions, 0 deletions
diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java new file mode 100644 index 000000000..620df282f --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java @@ -0,0 +1,484 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfapicall; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonWriter; + +import javax.ws.rs.core.UriBuilder; +import java.io.StringWriter; +import java.io.Writer; +import java.net.SocketException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +import org.onap.ccsdk.sli.plugins.restapicall.Format; +import org.onap.ccsdk.sli.plugins.restapicall.HttpResponse; +import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode; +import org.onap.ccsdk.sli.plugins.restapicall.XmlParser; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatSerializer; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatSerializerContext; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerFactory; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.Listener; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.MdsalSerializerHelper; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.SerializerHelper; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.YangParameters; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeSerializer; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeSerializer; +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; +import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Strings.repeat; +import static java.lang.String.format; +import static java.lang.String.valueOf; +import static org.apache.commons.lang3.StringUtils.join; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.DELETE; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.GET; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PATCH; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PUT; +import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.parseParam; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.ATTEMPTS_MSG; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COLON; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COMMA; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COMM_FAIL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HEADER; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HTTP_REQ; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HTTP_RES; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.MAX_RETRY_ERR; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.NO_MORE_RETRY; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.REQ_ERR; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.REST_API_URL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_CODE; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_MSG; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_PRE; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RETRY_COUNT; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RETRY_FAIL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.UPDATED_URL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getSchemaCtxFromDir; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getUpdatedXmlReq; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getYangParameters; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.parseUrl; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfListenerFactory.instance; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.UTF_HEADER; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_TREE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlWriter; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getModuleNamespace; +import static org.osgi.framework.FrameworkUtil.getBundle; + +/** + * Representation of a plugin to enable RESTCONF based CRUD operations from DG. + */ +public class RestconfApiCallNode implements SvcLogicJavaPlugin { + + /** + * Logger for the restconf api call node class. + */ + private static final Logger log = LoggerFactory.getLogger( + RestconfApiCallNode.class); + + /** + * Rest api call node service instance + */ + private RestapiCallNode restapiCallNode; + + /** + * Creates an instance of restconf api call node with restapi call node. + * + * @param r restapi call node + */ + public RestconfApiCallNode(RestapiCallNode r) { + this.restapiCallNode = r; + } + + /** + * Returns the restapi call node instance. + * @return + */ + public RestapiCallNode getRestapiCallNode() { + return restapiCallNode; + } + + /** + * Sends the restconf request using the parameters map and the memory + * context. And this method allows the directed graphs to interact with + * the restconf api call node + * + * @param paramMap parameters map + * @param ctx service logic context + * @throws SvcLogicException when svc logic exception occurs + */ + public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx) + throws SvcLogicException { + sendRequest(paramMap, ctx, 0); + } + + /** + * Sends the restconf request using the parameters map and the memory + * context along with the retry count. + * + * @param paramMap parameters map + * @param ctx service logic context + * @param retryCount number of retry counts + * @throws SvcLogicException when svc logic exception occurs + */ + public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx, + Integer retryCount) throws SvcLogicException { + RestapiCallNode rest = getRestapiCallNode(); + HttpResponse r = new HttpResponse(); + try { + YangParameters p = getYangParameters(paramMap); + + String pp = p.responsePrefix != null ? p.responsePrefix + '.' : ""; + Map<String, String> props = new HashMap<>((Map)ctx.toProperties()); + String uri = parseUrl(p.restapiUrl, p.httpMethod); + InstanceIdentifierContext<?> insIdCtx = getInsIdCtx(p, uri); + + String req = null; + if (p.httpMethod != GET && p.httpMethod != DELETE) { + req = serializeRequest(props, p, uri, insIdCtx); + if (p.httpMethod == PUT || p.httpMethod == PATCH) { + updateReq(req, p, insIdCtx); + } + } + if (req == null && p.requestBody != null) { + req = p.requestBody; + } + + r = rest.sendHttpRequest(req, p); + if (p.returnRequestPayload && req != null) { + ctx.setAttribute(pp + HTTP_REQ, req); + } + + String response = getResponse(ctx, p, pp, r); + if (response != null) { + try { + Map<String, String> resProp = serializeResponse( + p, uri, response, insIdCtx); + for (Map.Entry<String, String> pro : resProp.entrySet()) { + ctx.setAttribute(pro.getKey(), pro.getValue()); + } + } catch (SvcLogicException e) { + convertToNormalRes(ctx, p, pp, response); + } + } + } catch (SvcLogicException e) { + boolean shouldRetry = false; + if (e.getCause().getCause() instanceof SocketException) { + shouldRetry = true; + } + + log.error(REQ_ERR + e.getMessage(), e); + String prefix = parseParam(paramMap, RES_PRE, false, null); + setFailureResponseStatus(ctx, prefix, e.getMessage()); + } + + if (r != null && r.code >= 300) { + throw new SvcLogicException(valueOf(r.code) + + COLON + " " + r.message); + } + } + + private void convertToNormalRes(SvcLogicContext ctx , + YangParameters p, String pp, String body) + throws SvcLogicException { + if (p.convertResponse) { + Map<String, String> mm = null; + if (p.format == Format.XML) { + mm = XmlParser.convertToProperties(body, p.listNameList); + } else if (p.format == Format.JSON) { + mm = org.onap.ccsdk.sli.plugins.restapicall.JsonParser + .convertToProperties(body); + } + + if (mm != null) { + for (Map.Entry<String, String> entry : mm.entrySet()) { + ctx.setAttribute(pp + entry.getKey(), + entry.getValue()); + } + } + } + } + + /** + * Serializes the request message to JSON or XML from the properties. + * + * @param properties properties + * @param params YANG parameters + * @param uri URI + * @param insIdCtx instance identifier context + * @return JSON or XML message to be sent + * @throws SvcLogicException when serializing the request fails + */ + public String serializeRequest(Map<String, String> properties, + YangParameters params, String uri, + InstanceIdentifierContext insIdCtx) + throws SvcLogicException { + PropertiesNodeSerializer propSer = new MdsalPropertiesNodeSerializer( + insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri); + DataFormatSerializerContext serCtx = new DataFormatSerializerContext( + null, uri, null, propSer); + DataFormatSerializer ser = DfSerializerFactory.instance() + .getSerializer(serCtx, params); + //TODO: Handling of XML annotations + return ser.encode(properties, null); + } + + /** + * Serializes the response message from JSON or XML to the properties. + * + * @param params YANG parameters + * @param uri URI + * @param response response message + * @param insIdCtx instance identifier context + * @return response message as properties + * @throws SvcLogicException when serializing the response fails + */ + public Map<String, String> serializeResponse(YangParameters params, + String uri, String response, + InstanceIdentifierContext insIdCtx) + throws SvcLogicException { + PropertiesNodeSerializer propSer = new MdsalPropertiesNodeSerializer( + insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri); + SerializerHelper helper = new MdsalSerializerHelper( + insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri); + Listener listener = instance().getListener(helper, params); + DataFormatSerializerContext serCtx = new DataFormatSerializerContext( + listener, uri, null, propSer); + DataFormatSerializer ser = DfSerializerFactory.instance() + .getSerializer(serCtx, params); + return ser.decode(response); + } + + /** + * Returns instance identifier context for a uri using the schema context. + * + * @param params YANG parameters + * @param uri URI + * @return instance identifier context + * @throws SvcLogicException when getting schema context fails + */ + private InstanceIdentifierContext<?> getInsIdCtx(YangParameters params, + String uri) + throws SvcLogicException { + SchemaContext context = getSchemaContext(params); + return ParserIdentifier.toInstanceIdentifier(uri, context, null); + } + + /** + * Returns the global schema context or schema context of particular YANG + * files present in a directory path. + * + * @param params YANG parameters + * @return schema context + * @throws SvcLogicException when schema context fetching fails + */ + private SchemaContext getSchemaContext(YangParameters params) + throws SvcLogicException { + if (params.dirPath != null) { + return getSchemaCtxFromDir(params.dirPath); + } + BundleContext bc = getBundle(SchemaContext.class).getBundleContext(); + SchemaContext schemaContext = null; + if (bc != null) { + ServiceReference reference = bc.getServiceReference( + SchemaContext.class); + if (reference != null) { + schemaContext = (SchemaContext) bc.getService(reference); + } + } + return schemaContext; + } + + /** + * Returns the response message body of a http response message. + * + * @param ctx svc logic context + * @param params parameters + * @param pre prefix to be appended + * @param res http response + * @return response message body + */ + public String getResponse(SvcLogicContext ctx, YangParameters params, + String pre, HttpResponse res) { + ctx.setAttribute(pre + RES_CODE, valueOf(res.code)); + ctx.setAttribute(pre + RES_MSG, res.message); + + if (params.dumpHeaders && res.headers != null) { + for (Map.Entry<String, List<String>> a : res.headers.entrySet()) { + ctx.setAttribute(pre + HEADER + a.getKey(), + join(a.getValue(), COMMA)); + } + } + + if (res.body != null && res.body.trim().length() > 0) { + ctx.setAttribute(pre + HTTP_RES, res.body); + return res.body; + } + return null; + } + + /** + * Sets the failure response status in the context memory. + * + * @param ctx service logic context + * @param prefix prefix to be added + * @param errMsg error message + */ + private void setFailureResponseStatus(SvcLogicContext ctx, String prefix, + String errMsg) { + HttpResponse res = new HttpResponse(); + res.code = 500; + res.message = errMsg; + ctx.setAttribute(prefix + RES_CODE, valueOf(res.code)); + ctx.setAttribute(prefix + RES_MSG, res.message); + } + + /** + * Updates request message for JSON and XML data format, when the HTTP + * method points it as PUT or PATCH. + * + * @param req current request message + * @param p YANG parameters + * @param insIdCtx instance identifier context + * @return update request message + * @throws SvcLogicException when the data format type is wrong + */ + public String updateReq(String req, YangParameters p, + InstanceIdentifierContext<?> insIdCtx) + throws SvcLogicException { + + SchemaNode schemaNode = insIdCtx.getSchemaNode(); + Namespace modNs = getModuleNamespace(schemaNode.getQName(), + insIdCtx.getSchemaContext()); + String nodeName = schemaNode.getQName().getLocalName(); + + switch (p.format) { + case JSON: + return getUpdatedJsonReq(req, nodeName, modNs.moduleName()); + + case XML: + return getXmlReqForPutOp(req, nodeName, modNs.moduleNs()); + + default: + throw new SvcLogicException(format(FORMAT_ERR, p.format)); + } + } + + /** + * Returns the updated JSON request message, when the HTTP method + * points to PUT or PATCH. + * + * @param req current JSON request message + * @param nodeName root node name + * @param modName module name of the root node + * @return update JSON request message + */ + private String getUpdatedJsonReq(String req, String nodeName, + String modName) { + Writer writer = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(writer); + jsonWriter.setIndent(repeat(" ", 4)); + + JsonParser jsonParser = new JsonParser(); + JsonObject oldJson = (JsonObject)jsonParser.parse(req); + oldJson = remChildModName(oldJson, modName); + JsonObject newJson = new JsonObject(); + newJson.add(modName + COLON + nodeName, oldJson.deepCopy()); + + Gson gson= new Gson(); + gson.toJson(newJson, jsonWriter); + return writer.toString(); + } + + /** + * Removes module name from all the updated first level child node, if it + * is same as the root node added. + * + * @param oldJson JSON object for old request + * @param modName module name of root node + * @return JSON object for old request with updated child module name + */ + private JsonObject remChildModName(JsonObject oldJson, String modName) { + Iterator<Map.Entry<String, JsonElement>> it = oldJson.entrySet().iterator(); + Map<String, JsonElement> m = new HashMap<>(); + while (it.hasNext()) { + Map.Entry<String, JsonElement> jNode = it.next(); + if (jNode.getKey().contains(COLON)) { + String[] modArr = jNode.getKey().split(COLON); + if (modArr[0].equals(modName)) { + it.remove(); + m.put(modArr[1], jNode.getValue()); + } + } + } + if (!m.isEmpty()) { + for (Map.Entry<String, JsonElement> element : m.entrySet()) { + oldJson.add(element.getKey(), element.getValue()); + } + } + return oldJson; + } + + /** + * Returns the updated XML request message, when the HTTP method points + * to PUT or PATCH. + * + * @param req current JSON request message + * @param nodeName root node name + * @param modNs module namespace of the root node + * @return update JSON request message + * @throws SvcLogicException when XML parsing fails + */ + private String getXmlReqForPutOp(String req, String nodeName, + URI modNs) throws SvcLogicException { + req = getUpdatedXmlReq(req, nodeName, modNs.toString()); + Document oldDoc; + try { + oldDoc = DocumentHelper.parseText(req); + } catch (DocumentException e) { + throw new SvcLogicException(XML_TREE_ERR, e); + } + Writer writer = getXmlWriter( + UTF_HEADER + oldDoc.getRootElement().asXML(), "4"); + return writer.toString(); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java new file mode 100644 index 000000000..1309102b3 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java @@ -0,0 +1,265 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfapicall; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.restapicall.HttpMethod; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.YangParameters; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; +import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; + +import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.getParameters; +import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.parseParam; +import static org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode.DEFAULT_MODE; +import static org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource.forFile; +import static org.opendaylight.yangtools.yang.parser.rfc7950.reactor.RFC7950Reactors.defaultReactor; +import static org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource.create; + +/** + * Utilities for restconf api call node. + */ +public final class RestconfApiUtils { + + static final String RES_CODE = "response-code"; + + static final String HTTP_REQ ="httpRequest"; + + static final String RES_PRE = "responsePrefix"; + + static final String RES_MSG = "response-message"; + + static final String HEADER = "header."; + + static final String COMMA = ","; + + static final String COLON = ":"; + + static final String HTTP_RES = "httpResponse"; + + static final String REST_API_URL = "restapiUrl"; + + static final String UPDATED_URL = "URL was set to"; + + static final String COMM_FAIL = "Failed to communicate with host %s." + + "Request will be re-attempted using the host %s."; + + static final String RETRY_COUNT = "This is retry attempt %d out of %d"; + + static final String RETRY_FAIL = "Retry attempt has failed. No further " + + "retry shall be attempted, calling setFailureResponseStatus"; + + static final String NO_MORE_RETRY = "Could not attempt retry"; + + static final String MAX_RETRY_ERR = "Maximum retries reached, calling " + + "setFailureResponseStatus"; + + static final String ATTEMPTS_MSG = "%d attempts were made out of %d " + + "maximum retries"; + + static final String REQ_ERR = "Error sending the request: "; + + private static final String SLASH = "/"; + + private static final String DIR_PATH = "dirPath"; + + private static final String URL_SYNTAX = "The following URL cannot be " + + "parsed into URI : "; + + private static final String YANG = ".yang"; + + private static final String YANG_FILE_ERR = "Unable to parse the YANG " + + "file provided"; + + //No instantiation. + private RestconfApiUtils() { + } + + /** + * Returns the YANG parameters after parsing it from the map. + * + * @param paramMap parameters map + * @return YANG parameters + * @throws SvcLogicException when parsing of parameters map fail + */ + static YangParameters getYangParameters(Map<String, String> paramMap) + throws SvcLogicException { + YangParameters param = (YangParameters) getParameters( + paramMap, new YangParameters()); + param.dirPath = parseParam(paramMap, DIR_PATH, false, null); + return param; + } + + /** + * Parses the restconf URL and gives the YANG path from it, which can be + * used to get schema node. If it is a PUT operation, then a node must be + * reduced from the url to make it always point to the parent. + * + * @param url restconf URL + * @param method HTTP operation + * @return YANG path pointing to parent + * @throws SvcLogicException when parsing the URL fails + */ + public static String parseUrl(String url, HttpMethod method) + throws SvcLogicException { + URI uri; + try { + uri = new URI(url); + } catch (URISyntaxException e) { + throw new SvcLogicException(URL_SYNTAX + url, e); + } + + String path = uri.getPath(); + path = getParsedPath(path); + return path; + } + + /** + * Returns the path which contains only the schema nodes. + * + * @param path path + * @return path representing schema + */ + private static String getParsedPath(String path) { + String firstHalf; + String secondHalf; + if (path.contains(COLON)) { + String[] p = path.split(COLON); + if (p[0].contains(SLASH)) { + int slash = p[0].lastIndexOf(SLASH); + firstHalf = p[0].substring(slash + 1); + } else { + firstHalf = p[0]; + } + secondHalf = path.substring(p[0].length() + 1); + return firstHalf + COLON + secondHalf; + } else if (path.contains(SLASH)) { + String[] p = path.split(SLASH); + if (p.length > 4) { + String actual = p[3] + COLON + p[4]; + if (p.length > 5) { + secondHalf = path.substring( + p[1].length() + p[2].length() + actual.length() + 3); + path = actual + secondHalf; + } else { + path = actual; + } + } + } + return path; + } + + /** + * Returns the schema context of the YANG files present in a directory. + * + * @param di directory path + * @return YANG schema context + * @throws SvcLogicException when YANG file reading fails + */ + static SchemaContext getSchemaCtxFromDir(String di) + throws SvcLogicException { + Path d = Paths.get(di); + File dir = d.toFile(); + List<File> yangFiles = new LinkedList<>(); + getYangFiles(dir, yangFiles); + final Collection<YangStatementStreamSource> sources = + new ArrayList<>(yangFiles.size()); + for (File file : yangFiles) { + try { + sources.add(create(forFile(file))); + } catch (IOException | YangSyntaxErrorException e) { + throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e); + } + } + + final CrossSourceStatementReactor.BuildAction reactor = defaultReactor() + .newBuild(DEFAULT_MODE).addSources(sources); + try { + return reactor.buildEffective(); + } catch (ReactorException e) { + throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e); + } + } + + /** + * Returns all the YANG files present in a directory recursively. + * + * @param dir path of the directory + * @param yangFiles list of YANG files + */ + private static void getYangFiles(File dir, List<File> yangFiles) { + if (dir.exists()) { + File[] files = dir.listFiles(); + if (files != null) { + processFiles(files, yangFiles); + } + } + } + + /** + * Processes all the obtained files by isolating all the YANG files from + * all the directory of the given path recursively. + * + * @param files files in the given path + * @param yangFiles YANG files list + */ + private static void processFiles(File[] files, List<File> yangFiles) { + for (File file : files) { + if (file.isFile() && file.getName().endsWith(YANG)) { + yangFiles.add(file); + } else if (file.isDirectory()) { + getYangFiles(file, yangFiles); + } + } + } + + /** + * Returns the updated XML request message by adding root node to it. + * + * @param req XML request + * @param nodeName root node name + * @param modNs module namespace of the root node + * @return updated XML request message + */ + static String getUpdatedXmlReq(String req, String nodeName, String modNs) { + String rootNode = "\n<" + nodeName + " xmlns=\"" + modNs + + "\">\n"; + req = req.replaceFirst("\n", rootNode); + req = req + "</" + nodeName + ">"; + return req.replaceAll(">\\s+<", "><"); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/AdditionalHeaderWebTarget.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/AdditionalHeaderWebTarget.java new file mode 100644 index 000000000..3213cae15 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/AdditionalHeaderWebTarget.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Configuration; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; +import java.net.URI; +import java.util.Map; + +/** + * Adds additional headers for SSE request. + */ +class AdditionalHeaderWebTarget implements WebTarget { + private WebTarget base; + private String token; + + private String accessToken = "X-ACCESS-TOKEN"; + + public AdditionalHeaderWebTarget(WebTarget target, String token) { + base = target; + this.token = token; + } + + @Override + public Invocation.Builder request() { + return base.request().header(accessToken, token); + } + + @Override + public Invocation.Builder request(String... acceptedResponseTypes) { + return base.request().header(accessToken, token); + } + + @Override + public Invocation.Builder request(MediaType... acceptedResponseTypes) { + return base.request().header(accessToken, token); + } + + @Override + public Configuration getConfiguration() { + return base.getConfiguration(); + } + + @Override + public URI getUri() { + return base.getUri(); + } + + @Override + public UriBuilder getUriBuilder() { + return base.getUriBuilder(); + } + + @Override + public WebTarget path(String path) { + return base.path(path); + } + + @Override + public WebTarget resolveTemplate(String name, Object value) { + return base.resolveTemplate(name, value); + } + + @Override + public WebTarget resolveTemplate(String name, Object value, boolean encodeSlashInPath) { + return base.resolveTemplate(name, value, encodeSlashInPath); + } + + @Override + public WebTarget resolveTemplateFromEncoded(String name, Object value) { + return base.resolveTemplateFromEncoded(name, value); + } + + @Override + public WebTarget resolveTemplates(Map<String, Object> templateValues) { + return base.resolveTemplates(templateValues); + } + + @Override + public WebTarget resolveTemplates(Map<String, Object> templateValues, boolean encodeSlashInPath) { + return base.resolveTemplates(templateValues, encodeSlashInPath); + } + + @Override + public WebTarget resolveTemplatesFromEncoded(Map<String, Object> templateValues) { + return base.resolveTemplatesFromEncoded(templateValues); + } + + @Override + public WebTarget matrixParam(String name, Object... values) { + return base.matrixParam(name, values); + } + + @Override + public WebTarget queryParam(String name, Object... values) { + return base.queryParam(name, values); + } + + @Override + public WebTarget property(String name, Object value) { + return base.property(name, value); + } + + @Override + public WebTarget register(Class<?> componentClass) { + return base.register(componentClass); + } + + @Override + public WebTarget register(Class<?> componentClass, int priority) { + return base.register(componentClass, priority); + } + + @Override + public WebTarget register(Class<?> componentClass, Class<?>... contracts) { + return base.register(componentClass, contracts); + } + + @Override + public WebTarget register(Class<?> componentClass, Map<Class<?>, Integer> contracts) { + return base.register(componentClass, contracts); + } + + @Override + public WebTarget register(Object component) { + return base.register(component); + } + + @Override + public WebTarget register(Object component, int priority) { + return base.register(component, priority); + } + + @Override + public WebTarget register(Object component, Class<?>... contracts) { + return base.register(component, contracts); + } + + @Override + public WebTarget register(Object component, Map<Class<?>, Integer> contracts) { + return base.register(component, contracts); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventHandler.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventHandler.java new file mode 100644 index 000000000..a76554d5a --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventHandler.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.glassfish.jersey.media.sse.InboundEvent; +import org.glassfish.jersey.media.sse.EventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Listener that can be registered to listen for notifications. + */ +class EventHandler implements EventListener { + private static final Logger log = LoggerFactory.getLogger(EventListener.class); + private RestconfDiscoveryNode node; + + public EventHandler(RestconfDiscoveryNode node) { + this.node = node; + } + + @Override + public void onEvent(InboundEvent event) { + String payload = event.readData(); + if (!node.eventQueue().offer(payload)) { + log.error("Unable to process event {} as processing queue is full", payload); + } + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventProcessor.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventProcessor.java new file mode 100644 index 000000000..4f28072d3 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventProcessor.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.slf4j.Logger; + +import java.util.Map; + +import static org.onap.ccsdk.sli.plugins.restapicall.JsonParser.convertToProperties; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Processes the events from event queue and executes callback DG. + */ +class EventProcessor implements Runnable { + + private static final Logger log = getLogger(EventProcessor.class); + private RestconfDiscoveryNode node; + + private static final String EVENT_SUBSCRIPTION_ID = "notification." + + "push-change-update.subscription-id"; + + public EventProcessor(RestconfDiscoveryNode node) { + this.node = node; + } + + @Override + public void run() { + while(true) { + try { + String payload = node.eventQueue().take(); + Map<String, String> param = convertToProperties(payload); + String id = param.get(EVENT_SUBSCRIPTION_ID); + SubscriptionInfo info = node.subscriptionInfoMap().get(id); + if (info != null) { + SvcLogicContext ctx = setContext(param); + SvcLogicGraphInfo callbackDG = info.callBackDG(); + callbackDG.executeGraph(ctx); + } + } catch (InterruptedException | SvcLogicException e) { + log.error("Interrupted!", e); + Thread.currentThread().interrupt(); + } + } + } + + private SvcLogicContext setContext(Map<String, String> param) { + SvcLogicContext ctx = new SvcLogicContext(); + for (Map.Entry<String, String> entry : param.entrySet()) { + ctx.setAttribute(entry.getKey(), entry.getValue()); + } + return ctx; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/RestconfDiscoveryNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/RestconfDiscoveryNode.java new file mode 100644 index 000000000..cf69d7a3c --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/RestconfDiscoveryNode.java @@ -0,0 +1,310 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.glassfish.jersey.media.sse.EventSource; +import org.glassfish.jersey.media.sse.SseFeature; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.restapicall.Parameters; +import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode; +import org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode; +import org.slf4j.Logger; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Representation of a plugin to subscribe for notification and then + * to handle the received notifications. + */ +public class RestconfDiscoveryNode implements SvcLogicDiscoveryPlugin { + + private static final Logger log = getLogger(RestconfDiscoveryNode.class); + + private ExecutorService executor = Executors.newCachedThreadPool(); + private Map<String, PersistentConnection> runnableInfo = new ConcurrentHashMap<>(); + private RestconfApiCallNode restconfApiCallNode; + + private volatile Map<String, SubscriptionInfo> subscriptionInfoMap = new ConcurrentHashMap<>(); + private volatile LinkedBlockingQueue<String> eventQueue = new LinkedBlockingQueue<>(); + + private static final String SUBSCRIBER_ID = "subscriberId"; + private static final String RESPONSE_CODE = "response-code"; + private static final String RESPONSE_PREFIX = "responsePrefix"; + private static final String OUTPUT_IDENTIFIER = "ietf-subscribed-notif" + + "ications:establish-subscription.output.identifier"; + private static final String RESPONSE_CODE_200 = "200"; + private static final String SSE_URL = "sseConnectURL"; + + /** + * Creates an instance of RestconfDiscoveryNode and starts processing of + * event. + * + * @param r restconf api call node + */ + public RestconfDiscoveryNode(RestconfApiCallNode r) { + this.restconfApiCallNode = r; + ExecutorService e = Executors.newFixedThreadPool(20); + EventProcessor p = new EventProcessor(this); + for (int i = 0; i < 20; ++i) { + e.execute(p); + } + } + + @Override + public void establishSubscription(Map<String, String> paramMap, + SvcLogicContext ctx) throws SvcLogicException { + String subscriberId = paramMap.get(SUBSCRIBER_ID); + if (subscriberId == null) { + throw new SvcLogicException("Subscriber Id is null"); + } + + restconfApiCallNode.sendRequest(paramMap, ctx); + + if (getResponseCode(paramMap.get(RESPONSE_PREFIX), ctx).equals(RESPONSE_CODE_200)) { + // TODO: save subscription id and subscriber in MYSQL + + establishPersistentConnection(paramMap, ctx, subscriberId); + } else { + log.info("Failed to subscribe {}", subscriberId); + throw new SvcLogicException(ctx.getAttribute(RESPONSE_CODE)); + } + } + + @Override + public void modifySubscription(Map<String, String> paramMap, SvcLogicContext ctx) { + // TODO: to be implemented + } + + @Override + public void deleteSubscription(Map<String, String> paramMap, SvcLogicContext ctx) { + String id = getSubscriptionId(paramMap.get(SUBSCRIBER_ID)); + if (id != null) { + PersistentConnection conn = runnableInfo.get(id); + conn.terminate(); + runnableInfo.remove(id); + subscriptionInfoMap.remove(id); + } + } + + class PersistentConnection implements Runnable { + private String url; + private volatile boolean running = true; + private Map<String, String> paramMap; + + PersistentConnection(String url, Map<String, String> paramMap) { + this.url = url; + this.paramMap = paramMap; + } + + private void terminate() { + running = false; + } + + @Override + public void run() { + Parameters p; + WebTarget target = null; + try { + RestapiCallNode restapi = restconfApiCallNode.getRestapiCallNode(); + p = RestapiCallNode.getParameters(paramMap, new Parameters()); + Client client = ignoreSslClient().register(SseFeature.class); + target = restapi.addAuthType(client, p).target(url); + } catch (SvcLogicException e) { + log.error("Exception occured!", e); + Thread.currentThread().interrupt(); + } + + target = addToken(target, paramMap.get("customHttpHeaders")); + EventSource eventSource = EventSource.target(target).build(); + eventSource.register(new EventHandler(RestconfDiscoveryNode.this)); + eventSource.open(); + log.info("Connected to SSE source"); + while (running) { + try { + log.info("SSE state " + eventSource.isOpen()); + Thread.sleep(5000); + } catch (InterruptedException e) { + log.error("Interrupted!", e); + Thread.currentThread().interrupt(); + } + } + eventSource.close(); + log.info("Closed connection to SSE source"); + } + + private Client ignoreSslClient() { + SSLContext sslcontext = null; + + try { + sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(null, new TrustManager[]{new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } }, new java.security.SecureRandom()); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new IllegalStateException(e); + } + + return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build(); + } + } + + protected String getTokenId(String customHttpHeaders) { + if (customHttpHeaders.contains("=")) { + String[] s = customHttpHeaders.split("="); + return s[1]; + } + return customHttpHeaders; + } + + protected WebTarget addToken(WebTarget target, String customHttpHeaders) { + if (customHttpHeaders == null) { + return target; + } + + return new AdditionalHeaderWebTarget( + target, getTokenId(customHttpHeaders)); + } + + /** + * Establishes a persistent between the client and server. + * + * @param paramMap input paramter map + * @param ctx service logic context + * @param subscriberId subscriber identifier + */ + void establishPersistentConnection(Map<String, String> paramMap, SvcLogicContext ctx, + String subscriberId) { + String id = getOutputIdentifier(paramMap.get(RESPONSE_PREFIX), ctx); + SvcLogicGraphInfo callbackDG = new SvcLogicGraphInfo(paramMap.get("module"), + paramMap.get("rpc"), + paramMap.get("version"), + paramMap.get("mode")); + SubscriptionInfo info = new SubscriptionInfo(); + info.callBackDG(callbackDG); + info.subscriptionId(id); + info.subscriberId(subscriberId); + subscriptionInfoMap.put(id, info); + + String url = paramMap.get(SSE_URL); + PersistentConnection connection = new PersistentConnection(url, paramMap); + runnableInfo.put(id, connection); + executor.execute(connection); + } + + /** + * Returns response code. + * + * @param prefix prefix given in input parameter + * @param ctx service logic context + * @return response code + */ + String getResponseCode(String prefix, SvcLogicContext ctx) { + return ctx.getAttribute(getPrefix(prefix) + RESPONSE_CODE); + } + + /** + * Returns subscription id from event. + * + * @param prefix prefix given in input parameter + * @param ctx service logic context + * @return subscription id from event + */ + String getOutputIdentifier(String prefix, SvcLogicContext ctx) { + return ctx.getAttribute(getPrefix(prefix) + OUTPUT_IDENTIFIER); + } + + private String getPrefix(String prefix) { + return prefix != null ? prefix + "." : ""; + } + + private String getSubscriptionId(String subscriberId) { + for (Map.Entry<String,SubscriptionInfo> entry + : subscriptionInfoMap.entrySet()) { + if (entry.getValue().subscriberId() + .equals(subscriberId)) { + return entry.getKey(); + } + } + return null; + } + + /** + * Returns restconfApiCallNode. + * + * @return restconfApiCallNode + */ + protected RestconfApiCallNode restconfapiCallNode() { + return restconfApiCallNode; + } + + /** + * Sets restconfApiCallNode. + * + * @param node restconfApiCallNode + */ + void restconfapiCallNode(RestconfApiCallNode node) { + restconfApiCallNode = node; + } + + Map<String, SubscriptionInfo> subscriptionInfoMap() { + return subscriptionInfoMap; + } + + void subscriptionInfoMap(Map<String, SubscriptionInfo> subscriptionInfoMap) { + this.subscriptionInfoMap = subscriptionInfoMap; + } + + LinkedBlockingQueue<String> eventQueue() { + return eventQueue; + } + + void eventQueue(LinkedBlockingQueue<String> eventQueue) { + this.eventQueue = eventQueue; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SubscriptionInfo.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SubscriptionInfo.java new file mode 100644 index 000000000..4ed3660ca --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SubscriptionInfo.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +/** + * Holder to store information of subscription. + */ +public class SubscriptionInfo { + private String subscriptionId; + private String subscriberId; + private SvcLogicGraphInfo callbackDG; + private String yangFilePath; + private String filterUrl; + + /** + * Returns callback DG. + * + * @return callback DG + */ + public SvcLogicGraphInfo callBackDG() { + return callbackDG; + } + + /** + * Sets callback DG. + * + * @param callbackDg callback DG + */ + public void callBackDG(SvcLogicGraphInfo callbackDg) { + this.callbackDG = callbackDg; + } + + /** + * Returns YANG file path. + * + * @return YANG file path + */ + public String yangFilePath() { + return yangFilePath; + } + + /** + * Sets YANG file path. + * + * @param yangFilePath yang file path + */ + public void yangFilePath(String yangFilePath) { + this.yangFilePath = yangFilePath; + } + + /** + * Returns filter URL. + * + * @return filter URL + */ + public String filterUrl() { + return filterUrl; + } + + /** + * Sets filter URL. + * + * @param filterUrl filter URL + */ + public void filterUrl(String filterUrl) { + this.filterUrl = filterUrl; + } + + /** + * Returns subscription Id. + * + * @return subscription Id + */ + public String subscriptionId() { + return subscriptionId; + } + + /** + * Sets subscription id. + * + * @param subscriptionId subscription id + */ + public void subscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + } + + /** + * Returns subscription Id. + * + * @return subscription Id + */ + public String subscriberId() { + return subscriberId; + } + + /** + * Sets subscriber id. + * + * @param subscriberId subscriber id + */ + public void subscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicDiscoveryPlugin.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicDiscoveryPlugin.java new file mode 100644 index 000000000..dfe8cd5b7 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicDiscoveryPlugin.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import java.util.Map; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; + +/** + * Abstraction of a plugin to enable discovery from DG. + */ +public interface SvcLogicDiscoveryPlugin extends SvcLogicJavaPlugin { + + /** + * Allows directed graphs to establish a discovery subscription for a given subscriber. + * @param paramMap HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>templateDirName</td><td>Optional</td><td>full path to YANG directory that can be used to build a request</td><td>/sdncopt/bvc/resconfapi/test</td></tr> + * <tr><td>establishSubscriptionURL</td><td>Mandatory</td><td>url to establish connection with server</td><td>https://127.0.0.1:8181/restconf/operations/ietf-subscribed-notifications:establish-subscription</td></tr> + * <tr><td>sseConnectURL</td><td>Mandatory</td><td>url to setup SSE connection with server</td><td>https://127.0.0.1:8181/restconf/streams/yang-push-json</td></tr> + * <tr><td>callbackDG</td><td>Mandatory</td><td>callback DG to process the received notification</td><td>Resource-Discovery:handleSOTNTopology</td></tr> + * <tr><td>filterURL</td><td>Optional</td><td>url which needs to be subscribed, if null subscribe to all</td><td>http://example.com/sample-data/1.0</td></tr> + * <tr><td>subscriptionType</td><td>Optional</td><td>type of subscription, periodic or onDataChange</td><td>onDataChange</td></tr> + * <tr><td>updateFrequency</td><td>Optional</td><td>update frequency in milli seconds when subscription type is periodic</td><td>1000</td></tr> + * <tr><td>restapiUser</td><td>Optional</td><td>user name to use for http basic authentication</td><td>sdnc_ws</td></tr> + * <tr><td>restapiPassword</td><td>Optional</td><td>unencrypted password to use for http basic authentication</td><td>plain_password</td></tr> + * <tr><td>contentType</td><td>Optional</td><td>http content type to set in the http header</td><td>usually application/json or application/xml</td></tr> + * <tr><td>format</td><td>Optional</td><td>should match request body format</td><td>json or xml</td></tr> + * <tr><td>responsePrefix</td><td>Optional</td><td>location the notification response will be written to in context memory</td><td>tmp.restconfdiscovery.result</td></tr> + * <tr><td>skipSending</td><td>Optional</td><td></td><td>true or false</td></tr> + * <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr> + * <tr><td>customHttpHeaders</td><td>Optional</td><td>a list additional http headers to be passed in, follow the format in the example</td><td>X-CSI-MessageId=messageId,headerFieldName=headerFieldValue</td></tr> + * <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes http header content to context memory</td><td>true or false</td></tr> + * </tbody> + * </table> + * @param ctx Reference to context memory + * @throws SvcLogicException + * @since 11.0.2 + * @see String#split(String, int) + */ + void establishSubscription(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException; + + /** + * Allows directed graphs to modify a discovery subscription for a given subscriber. + * @param paramMap HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>subscriberId</td><td>Mandatory</td><td>subscription subscriber's identifier</td><td>topologyId/1111</td></tr> + * <tr><td>templateDirName</td><td>Optional</td><td>full path to YANG directory that can be used to build a request</td><td>/sdncopt/bvc/resconfapi/test</td></tr> + * <tr><td>establishSubscriptionURL</td><td>Mandatory</td><td>url to establish connection with server</td><td>https://127.0.0.1:8181/restconf/operations/ietf-subscribed-notifications:establish-subscription</td></tr> + * <tr><td>sseConnectURL</td><td>Mandatory</td><td>url to setup SSE connection with server</td><td>https://127.0.0.1:8181/restconf/streams/yang-push-json</td></tr> + * <tr><td>callbackDG</td><td>Mandatory</td><td>callback DG to process the received notification</td><td>Resource-Discovery:handleSOTNTopology</td></tr> + * <tr><td>filterURL</td><td>Optional</td><td>url filter list which needs to be subscribed, if null subscribe to all</td><td>http://example.com/sample-data/1.0</td></tr> + * <tr><td>subscriptionType</td><td>Optional</td><td>type of subscription, periodic or onDataChange</td><td>onDataChange</td></tr> + * <tr><td>updateFrequency</td><td>Optional</td><td>update frequency in milli seconds when subscription type is periodic</td><td>1000</td></tr> + * <tr><td>restapiUser</td><td>Optional</td><td>user name to use for http basic authentication</td><td>sdnc_ws</td></tr> + * <tr><td>restapiPassword</td><td>Optional</td><td>unencrypted password to use for http basic authentication</td><td>plain_password</td></tr> + * <tr><td>contentType</td><td>Optional</td><td>http content type to set in the http header</td><td>usually application/json or application/xml</td></tr> + * <tr><td>format</td><td>Optional</td><td>should match request body format</td><td>json or xml</td></tr> + * <tr><td>responsePrefix</td><td>Optional</td><td>location the notification response will be written to in context memory</td><td>tmp.restconfdiscovery.result</td></tr> + * <tr><td>skipSending</td><td>Optional</td><td></td><td>true or false</td></tr> + * <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr> + * <tr><td>customHttpHeaders</td><td>Optional</td><td>a list additional http headers to be passed in, follow the format in the example</td><td>X-CSI-MessageId=messageId,headerFieldName=headerFieldValue</td></tr> + * <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes http header content to context memory</td><td>true or false</td></tr> + * </tbody> + * </table> + * @param ctx Reference to context memory + * @throws SvcLogicException + * @since 11.0.2 + * @see String#split(String, int) + */ + void modifySubscription(Map<String, String> paramMap, SvcLogicContext ctx); + + /** + * Allows directed graphs to delete the discovery subscription for a given subscriber. + * @param paramMap HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>subscriberId</td><td>Mandatory</td><td>subscription subscriber's identifier</td><td>topologyId/1111</td></tr> + * </tbody> + * </table> + * @param ctx Reference to context memory + * @throws SvcLogicException + */ + void deleteSubscription(Map<String, String> paramMap, SvcLogicContext ctx); + +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicGraphInfo.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicGraphInfo.java new file mode 100644 index 000000000..1cc6261ab --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicGraphInfo.java @@ -0,0 +1,178 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicGraph; +import org.onap.ccsdk.sli.core.sli.SvcLogicStore; +import org.onap.ccsdk.sli.core.sli.provider.SvcLogicService; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; + +/** + * Holder to store callback directed graph info. + */ +class SvcLogicGraphInfo { + private String module; + private String rpc; + private String mode; + private String version; + + /** + * Creates an instance of SvcLogicGraphInfo. + * + * @param module module name of callback DG + * @param rpc rpc name of callback DG + * @param mode mode of callback DG + * @param version version of callback DG + */ + public SvcLogicGraphInfo(String module, String rpc, String mode, String version) { + this.module = module; + this.rpc = rpc; + this.mode = mode; + this.version = version; + } + + public SvcLogicGraphInfo() {} + + /** + * Returns module name of callback DG. + * + * @return module name of callback DG + */ + public String module() { + return module; + } + + /** + * Sets module of callback DG. + * + * @param module module name of the DG + */ + public void module(String module) { + this.module = module; + } + + /** + * Returns rpc of callback DG. + * + * @return rpc of callback DG + */ + public String rpc() { + return rpc; + } + + /** + * Sets rpc of callback DG. + * + * @param rpc rpc attribute of the DG + */ + public void rpc(String rpc) { + this.rpc = rpc; + } + + /** + * Returns mode of callback DG. + * + * @return mode of callback DG + */ + public String mode() { + return mode; + } + + /** + * Sets mode of DG. + * + * @param mode mode of the DG + */ + public void mode(String mode) { + this.mode = mode; + } + + /** + * Returns version of callback DG. + * + * @return version of callback DG + */ + public String version() { + return version; + } + + /** + * Sets version of DG. + * + * @param version version of the DG + */ + public void version(String version) { + this.version = version; + } + + /** + * Executes call back DG. + * + * @param ctx service logic context + * @throws SvcLogicException service logic error + */ + public void executeGraph(SvcLogicContext ctx) throws SvcLogicException { + SvcLogicService service = findSvcLogicService(); + if (service == null) { + throw new SvcLogicException("\"Could not get SvcLogicService reference\""); + } + + SvcLogicStore store = service.getStore(); + if (store != null) { + SvcLogicGraph subGraph = store.fetch(module, rpc, mode, version); + if (subGraph != null) { + ctx.setAttribute("subGraph", subGraph.toString()); + service.execute(subGraph, ctx); + } else { + throw new SvcLogicException("Failed to call child [" + module + + "," + rpc + "," + version + + "," + mode + "] because" + + " the" + " graph could" + + " not be found"); + } + } else { + throw new SvcLogicException("\"Could not get SvcLogicStore reference\""); + } + } + + private static SvcLogicService findSvcLogicService() throws SvcLogicException { + Bundle bundle = FrameworkUtil.getBundle(SvcLogicService.class); + if (bundle == null) { + throw new SvcLogicException("Cannot find bundle reference for " + + SvcLogicService.NAME); + } + + BundleContext bctx = bundle.getBundleContext(); + ServiceReference<SvcLogicService> sref = bctx.getServiceReference( + SvcLogicService.class); + if (sref != null) { + return bctx.getService(sref); + } else { + throw new SvcLogicException("Cannot find service reference for " + + SvcLogicService.NAME); + } + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Annotation.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Annotation.java new file mode 100644 index 000000000..185f70ba0 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Annotation.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Representation of an entity that represents annotated attribute. + */ +public class Annotation { + + /** + * Name of the annotation. + */ + private String name; + + /** + * Value of the annotation. + */ + private String value; + + /** + * Creates an instance of annotation. + * + * @param n annotation name + * @param v annotation value + */ + public Annotation(String n, String v) { + name = n; + value = v; + } + + /** + * Returns name of annotation. + * + * @return name of annotation + */ + public String name() { + return name; + } + + /** + * Returns value of annotation. + * + * @return value of annotation + */ + public String value() { + return value; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormat.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormat.java new file mode 100644 index 000000000..c692f1dd2 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormat.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Representation of data format. + */ +public enum DataFormat { + + /** + * XML data format. + */ + XML, + + /** + * JSON data format. + */ + JSON +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java new file mode 100644 index 000000000..cab64391a --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.List; +import java.util.Map; + +/** + * Abstraction of serializer to encode/decode context memory parameters + * to/from specified data format. + */ +public abstract class DataFormatSerializer { + + /** + * Data format type of the serializer. + */ + private DataFormat dataFormat; + + /** + * Data format serializer context. + */ + private DataFormatSerializerContext serializerContext; + + /** + * Creates an instance of data format serializer. + * + * @param d type of data format + * @param s data format serializer context + */ + protected DataFormatSerializer(DataFormat d, + DataFormatSerializerContext s) { + this.dataFormat = d; + this.serializerContext = s; + } + + /** + * Encodes context memory parameters to data format. + * + * @param param context memory parameter + * @param annotations annotations + * @return data format body + * @throws SvcLogicException when serialization fails + */ + public abstract String encode(Map<String, String> param, + Map<String, List<Annotation>> annotations) throws SvcLogicException; + + /** + * Decodes data format body to context memory parameters. + * + * @param dataFormatBody abstract node + * @return context memory parameters + * @throws SvcLogicException when serialization fails + */ + public abstract Map<String, String> decode(String dataFormatBody) + throws SvcLogicException; + + /** + * Returns data format serializer context. + * + * @return data format serializer context + */ + public DataFormatSerializerContext serializerContext() { + return serializerContext; + } + + /** + * Returns supported data format. + * + * @return supported data format + */ + public DataFormat dataFormat() { + return dataFormat; + } +}
\ No newline at end of file diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerContext.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerContext.java new file mode 100644 index 000000000..919e82af3 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerContext.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeSerializer; + +import java.util.Map; + +/** + * Abstraction of data format serializer context. + */ +public class DataFormatSerializerContext { + + /** + * Data format listener. + */ + private Listener listener; + + /** + * URI corresponding to the instance identifier. + */ + private String uri; + + /** + * Protocol annotation. + */ + private Map<String, String> protocolAnnotation; + + /** + * Properties node serializer. + */ + private PropertiesNodeSerializer propNodeSerializer; + + /** + * Creates an instance of data format serializer context. + * + * @param l data format listener + * @param u URI corresponding to instance identifier + * @param p protocol annotations + * @param s properties node serializer + */ + public DataFormatSerializerContext(Listener l, String u, + Map<String, String> p, + PropertiesNodeSerializer s) { + listener = l; + uri = u; + protocolAnnotation = p; + propNodeSerializer = s; + } + + /** + * Returns the data format listener. + * + * @return data format listener + */ + public Listener listener() { + return listener; + } + + /** + * Returns the URI. + * + * @return URI + */ + public String uri() { + return uri; + } + + /** + * Returns the protocol annotations. + * + * @return protocol annotations + */ + public Map<String, String> getProtocolAnnotation() { + return protocolAnnotation; + } + + /** + * Returns the properties node serializer. + * + * @return properties node serializer + */ + public PropertiesNodeSerializer getPropNodeSerializer() { + return propNodeSerializer; + } +}
\ No newline at end of file diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java new file mode 100644 index 000000000..45317522a --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java @@ -0,0 +1,145 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; + + +/** + * Representation of default implementation of JSON listener. + */ +public class DefaultJsonListener implements JsonListener { + + /** + * Serializer helper to convert to properties node. + */ + private SerializerHelper serializerHelper; + + /** + * Name of the current JSON node. + */ + private String name; + + /** + * Module name of the current JSON node. + */ + private String modName; + + /** + * Value of the current JSON node. + */ + private String value; + + /** + * Value namespace of the current JSON node. + */ + private String valueNs; + + /** + * Creates an instance of default json listener with its serializer helper. + * + * @param serializerHelper serializer helper + */ + public DefaultJsonListener(SerializerHelper serializerHelper) { + this.serializerHelper = serializerHelper; + } + + @Override + public void enterJsonNode(String nodeName, JsonNode node, + NodeType nodeType) throws SvcLogicException { + getNodeName(nodeName, false); + + switch (nodeType) { + case SINGLE_INSTANCE_LEAF_NODE: + getNodeName(node.asText(), true); + serializerHelper.addNode(name, modName, value, valueNs, + SINGLE_INSTANCE_LEAF_NODE); + break; + + case MULTI_INSTANCE_LEAF_NODE: + getNodeName(node.asText(), true); + serializerHelper.addNode(name, modName, value, valueNs, + MULTI_INSTANCE_LEAF_NODE); + break; + + case SINGLE_INSTANCE_NODE: + serializerHelper.addNode(name, modName, null, null, + SINGLE_INSTANCE_NODE); + break; + + case MULTI_INSTANCE_NODE: + serializerHelper.addNode(name, modName, null, null, + MULTI_INSTANCE_NODE); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + nodeType.toString())); + } + } + + @Override + public void exitJsonNode(JsonNode node) throws SvcLogicException { + serializerHelper.exitNode(); + } + + @Override + public SerializerHelper serializerHelper() { + return serializerHelper; + } + + /** + * Parses the abstract JSON name and fills the node name and node + * namespace or value and value namespace of the current JSON node . + * + * @param abstractName full name value + * @param isVal if it is for value parsing + */ + private void getNodeName(String abstractName, boolean isVal) { + String[] val = abstractName.split(":"); + if (val.length == 2) { + if (isVal) { + valueNs = val[0]; + value = val[1]; + } else { + modName = val[0]; + name = val[1]; + } + } else { + if (isVal) { + value = val[0]; + valueNs = null; + } else { + name = val[0]; + modName = null; + } + } + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java new file mode 100644 index 000000000..47cb8b292 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeType; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; + +import java.util.Iterator; +import java.util.Map; + +import static com.fasterxml.jackson.databind.node.JsonNodeType.NUMBER; +import static com.fasterxml.jackson.databind.node.JsonNodeType.STRING; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; + +/** + * Implementation of JSON walker to walk through the nodes and process it. + */ +public class DefaultJsonWalker implements JsonWalker { + + @Override + public void walk(JsonListener listener, JsonNode jsonNode) throws + SvcLogicException { + Iterator<Map.Entry<String, JsonNode>> children = jsonNode.fields(); + while (children.hasNext()) { + Map.Entry<String, JsonNode> child = children.next(); + JsonNode value = child.getValue(); + String key = child.getKey(); + if (value.isArray()) { + processMultiNodes(key, value, listener); + } else { + processSingleNode(key, value, listener); + } + } + } + + /** + * Processes single instance node or leaf, by adding the node to from + * JSON and walking through all its children recursively. + * + * @param key JSON name + * @param value JSON node + * @param listener JSON listener + * @throws SvcLogicException when processing the node fails + */ + private void processSingleNode(String key, JsonNode value, + JsonListener listener) + throws SvcLogicException { + NodeType nodeType; + if (!value.isContainerNode()) { + nodeType = SINGLE_INSTANCE_LEAF_NODE; + } else { + nodeType = SINGLE_INSTANCE_NODE; + } + processNode(key, value, nodeType, listener); + } + + /** + * Processes multi instance node or leaf, by adding the node to from JSON + * and walking through all its instance recursively. + * + * @param key JSON name + * @param value JSON node + * @param listener JSON listener + * @throws SvcLogicException when processing a single instance fails + */ + private void processMultiNodes(String key, JsonNode value, + JsonListener listener) + throws SvcLogicException { + NodeType nodeType; + Iterator<JsonNode> multiNodes = value.elements(); + while (multiNodes.hasNext()) { + if (isLeafListNode((ArrayNode) value)) { + nodeType = MULTI_INSTANCE_LEAF_NODE; + } else { + nodeType = MULTI_INSTANCE_NODE; + } + JsonNode multiNode = multiNodes.next(); + processNode(key, multiNode, nodeType, listener); + } + } + + /** + * Processes each node by first entering the JSON node through JSON + * listener, second a call back to walking the rest of the tree of the + * node and finally exiting the node. + * + * @param key JSON name + * @param node JSON node + * @param nodeType JSON node type + * @param listener JSON listener + * @throws SvcLogicException when entering a JSON node fails + */ + private void processNode(String key, JsonNode node, NodeType nodeType, + JsonListener listener) throws SvcLogicException { + listener.enterJsonNode(key, node, nodeType); + walk(listener, node); + listener.exitJsonNode(node); + } + + /** + * Returns true if the node corresponds to a leaf-list node; false + * otherwise. + * + * @param node JSON node + * @return true if node corresponds to leaf-list node; false otherwise + */ + private boolean isLeafListNode(ArrayNode node) { + Iterator<JsonNode> children = node.elements(); + while (children.hasNext()) { + JsonNodeType type = children.next().getNodeType(); + if (type != STRING && type != NUMBER) { + return false; + } + } + return true; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java new file mode 100644 index 000000000..03abf44fd --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.dom4j.Namespace; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.List; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; + +/** + * Representation of default implementation of XML listener. + */ +public class DefaultXmlListener implements XmlListener { + + /** + * Serializer helper to convert to properties node. + */ + private SerializerHelper serializerHelper; + + /** + * Creates an instance of default XML listener with its serializer helper. + * + * @param serializerHelper serializer helper + */ + public DefaultXmlListener(SerializerHelper serializerHelper) { + this.serializerHelper = serializerHelper; + } + + @Override + public void enterXmlElement(Element element, XmlNodeType nodeType) + throws SvcLogicException { + switch (nodeType) { + case TEXT_NODE: + serializerHelper.addNode(element.getName(), + element.getNamespace().getURI(), + element.getText(), null, null); + break; + + case OBJECT_NODE: + List cont = element.content(); + if (cont != null && cont.size() == 2 && + isValueNsForLeaf(cont, element)) { + return; + } + serializerHelper.addNode(element.getName(), + element.getNamespace().getURI(), + null, null, null); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + nodeType.toString())); + } + } + + /** + * Returns true if element has value namespace and adds the node to + * property tree; false otherwise. + * + * @param cont content of the element + * @param element element + * @return true if element has value namespace; false otherwise + * @throws SvcLogicException + */ + private boolean isValueNsForLeaf(List cont, Element element) + throws SvcLogicException { + for (Object c : cont) { + if (c instanceof Namespace) { + String value = element.getText(); + if (value != null) { + String[] val = value.split(":"); + String valPrefix = val[0]; + String actVal = val[1]; + if (valPrefix != null && actVal != null && + valPrefix.equals(((Namespace) c).getPrefix())) { + serializerHelper.addNode( + element.getName(), + element.getNamespace().getURI(), + actVal, + ((Namespace) c).getURI(), null); + return true; + } + } + } + } + return false; + } + + @Override + public void exitXmlElement(Element element) throws SvcLogicException { + serializerHelper.exitNode(); + } + + @Override + public SerializerHelper serializerHelper() { + return serializerHelper; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java new file mode 100644 index 000000000..cdc713f31 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.Iterator; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlNodeType; + +/** + * Implementation of XML walker to walk through the nodes and process it. + */ +public class DefaultXmlWalker implements XmlWalker { + + @Override + public void walk(XmlListener listener, Element xmlElement) throws + SvcLogicException { + listener.enterXmlElement(xmlElement, getXmlNodeType(xmlElement)); + if (xmlElement.hasContent() && !xmlElement.isTextOnly()) { + Iterator i = xmlElement.elementIterator(); + while (i.hasNext()) { + Element childElement = (Element) i.next(); + walk(listener, childElement); + } + } + listener.exitXmlElement(xmlElement); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java new file mode 100644 index 000000000..06a811e15 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; + +/** + * Represents the data format listener factory which will return JSON or XML + * listener according to the serializer helper. + */ +public final class DfListenerFactory { + + /** + * Creates a new DfListenerFactory. + */ + private DfListenerFactory() { + } + + /** + * Returns the instance of the data format listener factory. + * + * @return instance of the data format listener factory + */ + public static DfListenerFactory instance() { + return DfListenerFactory.LazyHolder.INSTANCE; + } + + /** + * Bill pugh singleton pattern. Instance will not be instantiated until + * the lazy holder class is loaded via a call to the instance of method + * below. + */ + private static class LazyHolder { + private static final DfListenerFactory INSTANCE = + new DfListenerFactory(); + } + + /** + * Returns the data format listener by deciding it based on the format of + * the parameter. + * + * @param serHelper serializer helper + * @param params parameters + * @return data format listener + * @throws SvcLogicException when the data format type is wrong + */ + public Listener getListener(SerializerHelper serHelper, + YangParameters params) + throws SvcLogicException { + Listener listener; + switch (params.format) { + case JSON: + listener = new DefaultJsonListener(serHelper); + break; + + case XML: + listener = new DefaultXmlListener(serHelper); + break; + + default: + throw new SvcLogicException(format(FORMAT_ERR, + params.format)); + } + return listener; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java new file mode 100644 index 000000000..4d95235e5 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; + +/** + * Represents the data format serializer factory which will return JSON or XML + * serializer according to the serializer context. + */ +public final class DfSerializerFactory { + + /** + * Creates a new DfSerializerFactory. + */ + private DfSerializerFactory() { + } + + /** + * Returns the instance of the data format serializer factory. + * + * @return instance of the data format serializer factory + */ + public static DfSerializerFactory instance() { + return DfSerializerFactory.LazyHolder.INSTANCE; + } + + /** + * Bill pugh singleton pattern. Instance will not be instantiated until + * the lazy holder class is loaded via a call to the instance of method + * below. + */ + private static class LazyHolder { + private static final DfSerializerFactory INSTANCE = + new DfSerializerFactory(); + } + + /** + * Returns the data format serializer by deciding it based on the format of + * the parameter. + * + * @param serCtx serializer context + * @param params parameters + * @return data format serializer + * @throws SvcLogicException when the data format type is wrong + */ + public DataFormatSerializer getSerializer(DataFormatSerializerContext serCtx, + YangParameters params) + throws SvcLogicException { + DataFormatSerializer serializer; + switch (params.format) { + case JSON: + serializer = new JsonSerializer(serCtx); + break; + + case XML: + serializer = new XmlSerializer(serCtx); + break; + + default: + throw new SvcLogicException(format(FORMAT_ERR, + params.format)); + } + return serializer; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java new file mode 100644 index 000000000..707c29444 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java @@ -0,0 +1,231 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Iterator; + +import static javax.xml.transform.OutputKeys.INDENT; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.OBJECT_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.TEXT_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; + +/** + * Utilities for data format serializer. + */ +public final class DfSerializerUtil { + + static final String JSON_WRITE_ERR = "Unable to write to JSON from " + + "properties."; + + static final String NODE_TYPE_ERR = "The node type %s is not supported."; + + static final String JSON_LIS_ERR = "The JSON serializer doesn't have " + + "JSON listener"; + + static final String XML_LIS_ERR = "The XML serializer doesn't have XML " + + "listener"; + + static final String PROP_NODE_ERR = "The property node doesn't have " + + "schema node bound to it."; + + static final String DF_ERR = "Type mismatch for the node %s. The schema " + + "node does not match with the data format node type %s."; + + static final String XML_PREFIX = "yangid"; + + private static final String YES = "yes"; + + private static final String INDENT_XMLNS = "{http://xml.apache" + + ".org/xslt}indent-amount"; + + private static final String XML_PARSE_ERR = "Unable to parse the xml to " + + "document : \n"; + + private static final String URI_ERR = "Unable to parse the URI"; + + /** + * Data format error message for unsupported types. + */ + public static final String FORMAT_ERR = "Only JSON and XML formats are " + + "supported. %s is not supported"; + + /** + * UTF header message for XML data format message. + */ + public static final String UTF_HEADER = "<?xml version=\"1.0\" " + + "encoding=\"UTF-8\"?>"; + + /** + * Error message when a JSON tree creation fails. + */ + public static final String JSON_TREE_ERR = "Unable to form JSON tree " + + "object from the JSON body provided."; + + /** + * Error message when a XML tree creation fails. + */ + public static final String XML_TREE_ERR = "Unable to form XML tree object" + + " from the XML body provided."; + + //No instantiation. + private DfSerializerUtil() { + } + + /** + * Returns the writer which contains the pretty formatted XML string. + * + * @param input input XML + * @param indent indentation level + * @return writer with XML + * @throws SvcLogicException when transformation of source fails + */ + public static Writer getXmlWriter(String input, String indent) + throws SvcLogicException { + try { + Transformer transformer = TransformerFactory.newInstance() + .newTransformer(); + transformer.setOutputProperty(INDENT, YES); + transformer.setOutputProperty(INDENT_XMLNS, indent); + StreamResult result = new StreamResult(new StringWriter()); + DOMSource source = new DOMSource(parseXml(input)); + transformer.transform(source, result); + return result.getWriter(); + } catch (TransformerException e) { + throw new SvcLogicException(XML_PARSE_ERR + input, e); + } + } + + /** + * Parses the XML and converts it into dom document which can be used for + * formatting the XML. + * + * @param in input XML + * @return dom document of XML + * @throws SvcLogicException when document building fails + */ + private static Document parseXml(String in) throws SvcLogicException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + InputSource is = new InputSource(new StringReader(in)); + return db.parse(is); + } catch (SAXException | IOException | ParserConfigurationException e) { + throw new SvcLogicException(XML_PARSE_ERR + in, e); + } + } + + /** + * Returns the resolved namespace object from the input received from the + * abstract data format. + * + * @param mName module name + * @param mUri module URI + * @param ctx schema context + * @param parent parent properties node + * @return namespace + * @throws SvcLogicException when resolving namespace fails + */ + static Namespace getResolvedNamespace(String mName, String mUri, + SchemaContext ctx, + PropertiesNode parent) + throws SvcLogicException { + if (mName == null && mUri == null) { + Namespace parentNs = parent.namespace(); + return new Namespace(parentNs.moduleName(), parentNs.moduleNs(), + parentNs.revision()); + } + + Iterator<Module> it; + Module mod; + if (mName != null) { + it = ctx.findModules(mName).iterator(); + } else { + URI modUri = null; + try { + modUri = new URI(mUri); + } catch (URISyntaxException e) { + throw new SvcLogicException(URI_ERR, e); + } + it = ctx.findModules(modUri).iterator(); + } + + if (!it.hasNext()) { + return null; + } + mod = it.next(); + + return new Namespace(mod.getName(), mod.getQNameModule().getNamespace(), + getRevision(mod.getRevision())); + } + + /** + * Returns the node type of a XML element. + * + * @param element XML element + * @return node type of the XML element + */ + static XmlNodeType getXmlNodeType(Element element) { + Element newElement = element.createCopy(); + newElement.remove(element.getNamespace()); + return newElement.hasContent() && newElement.isTextOnly() ? + TEXT_NODE : OBJECT_NODE; + } + + /** + * Resolves the super type to the base type from type definition. + * + * @param type super type + * @return base type definition + */ + static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) { + TypeDefinition superType = type; + while (superType.getBaseType() != null) { + superType = superType.getBaseType(); + } + return superType; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java new file mode 100644 index 000000000..89fd4c8c8 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; + +/** + * Abstraction of an entity which provides call back methods, which in turn + * are called by JSON walker while walking the JSON tree. This interface + * needs to be implemented by protocol, implementing listener based call + * while doing JSON walk. + */ +public interface JsonListener extends Listener { + + /** + * Call back invoked during JSON node entry. All other related + * information can be obtained from the JSON node. + * + * @param nodeName JSON node name + * @param node JSON node + * @param nodeType JSON node type + * @throws SvcLogicException when node type is of wrong format + */ + void enterJsonNode(String nodeName, JsonNode node, NodeType nodeType) + throws SvcLogicException; + + /** + * Call back invoked during JSON node exit. All the related information + * can be obtained from the JSON node. + * + * @param node JSON node + * @throws SvcLogicException when JSON node exit doesn't happen + */ + void exitJsonNode(JsonNode node) throws SvcLogicException; +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java new file mode 100644 index 000000000..91adb8126 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeWalker; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormat.JSON; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.JSON_LIS_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.JSON_TREE_ERR; + +/** + * Representation of JSON serializer which encodes properties to JSON and + * decodes properties from JSON with the data format serializer. + */ +public class JsonSerializer extends DataFormatSerializer { + + /** + * Creates an instance of data format serializer. + * + * @param serializerContext data format serializer context + */ + protected JsonSerializer(DataFormatSerializerContext serializerContext) { + super(JSON, serializerContext); + } + + @Override + public String encode(Map<String, String> param, + Map<String, List<Annotation>> annotations) + throws SvcLogicException { + PropertiesNode propNode = serializerContext().getPropNodeSerializer() + .encode(param); + PropertiesNodeWalker nodeWalker = new DefaultPropertiesNodeWalker<>(); + PropertiesNodeJsonListener jsonLis = new PropertiesNodeJsonListener(); + nodeWalker.walk(jsonLis, propNode); + Writer writer = jsonLis.getWriter(); + return writer.toString(); + } + + @Override + public Map<String, String> decode(String dataFormatBody) + throws SvcLogicException { + if (!(serializerContext().listener() instanceof JsonListener)) { + throw new SvcLogicException(JSON_LIS_ERR); + } + + JsonListener listener = (JsonListener) serializerContext().listener(); + JsonWalker walker = new DefaultJsonWalker(); + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode; + + try { + jsonNode = mapper.readTree(dataFormatBody); + } catch (IOException e) { + throw new SvcLogicException(JSON_TREE_ERR, e); + } + + walker.walk(listener, jsonNode); + + return serializerContext().getPropNodeSerializer().decode( + listener.serializerHelper().getPropertiesNode()); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java new file mode 100644 index 000000000..588070a12 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of an entity which provides interface for JSON walk. This + * interface serves as a common tool for anyone who needs to parse the JSON + * node with depth-first algorithm. + */ +public interface JsonWalker { + + /** + * Walks the JSON data tree. Protocols implement JSON listener service + * and walks the JSON tree with input as implemented object. JSON walker + * provides call back to the implemented methods. + * + * @param listener JSON listener implemented by the protocol + * @param jsonNode root node of the JSON data tree + * @throws SvcLogicException when walking the JSON node fails + */ + void walk(JsonListener listener, JsonNode jsonNode) + throws SvcLogicException; +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Listener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Listener.java new file mode 100644 index 000000000..e5812dbb7 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Listener.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Abstraction of listener. + */ +public interface Listener { + + /** + * Returns serializer helper for this listener. + * + * @return serializer helper + */ + SerializerHelper serializerHelper(); +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java new file mode 100644 index 000000000..1fd0d2dee --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java @@ -0,0 +1,297 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; + +import java.util.Deque; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.DF_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.PROP_NODE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getResolvedNamespace; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.resolveBaseTypeFrom; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findDataChildSchemaByQName; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findSchemaForChild; +import static org.opendaylight.yangtools.yang.data.util.ParserStreamUtils.findSchemaNodeByNameAndNamespace; + +/** + * Representation of MDSAL based serializer helper, which adds properties + * node to the properties tree based on its types. + */ +public class MdsalSerializerHelper extends SerializerHelper<SchemaNode, SchemaContext> { + + /** + * Current properties node. + */ + private PropertiesNode propNode; + + /** + * Current schema node. + */ + private SchemaNode curSchemaNode; + + + /** + * Creates MDSAL serializer helper with root schema node, schema context + * and URI. + * + * @param n schema node of the URI's last node + * @param c schema context + * @param u URI of the request + */ + public MdsalSerializerHelper(SchemaNode n, SchemaContext c, + String u) { + super(n, c, u); + Namespace ns = new Namespace(n.getQName().getLocalName(), + n.getQName().getNamespace(), + getRevision(n.getQName().getRevision())); + propNode = new RootNode<>(n.getQName().getLocalName(), ns, + getSchemaNode(), u); + curSchemaNode = getSchemaNode(); + } + + @Override + protected SchemaNode getSchemaNode() { + return schemaNode; + } + + @Override + protected SchemaContext getSchemaCtx() { + return schemaCtx; + } + + @Override + protected SchemaNode getCurSchema() { + return curSchemaNode; + } + + @Override + protected void addNode(String name, String nameSpace, String value, + String valNameSpace, NodeType type) + throws SvcLogicException { + Namespace ns; + if (type == null) { + ns = getResolvedNamespace(null, nameSpace, + getSchemaCtx(), propNode); + } else { + ns = getResolvedNamespace(nameSpace, null, + getSchemaCtx(), propNode); + } + if (isChildPresent(name, ns)) { + addNodeToProperty(name, ns, value, valNameSpace, type); + } else { + throw new SvcLogicException(format( + "Unable to add the node %s", name)); + } + } + + @Override + protected void exitNode() throws SvcLogicException { + propNode = propNode.parent(); + if (propNode != null) { + NodeType type = propNode.nodeType(); + if (type == MULTI_INSTANCE_HOLDER_NODE || + type == MULTI_INSTANCE_LEAF_HOLDER_NODE) { + propNode = propNode.parent(); + } + } + if (propNode == null || propNode.appInfo() == null + || !(propNode.appInfo() instanceof SchemaNode)) { + throw new SvcLogicException(PROP_NODE_ERR); + } + curSchemaNode = (SchemaNode) propNode.appInfo(); + } + + @Override + protected PropertiesNode getPropertiesNode() { + return propNode; + } + + /** + * Adds the node to property node based on the type of the schema node, + * which is decided based on the name and namespace of the input + * information. + * + * @param name name of the node + * @param ns namespace of the node + * @param value value of the node if its a leaf/leaf-list + * @param valNamespace namespace of the value + * @param type type of the node + * @throws SvcLogicException when adding child fails + */ + private void addNodeToProperty(String name, Namespace ns, String value, + String valNamespace, NodeType type) + throws SvcLogicException { + Namespace valueNs; + if (type != null) { + validateNodeType(type); + } + if (curSchemaNode instanceof LeafSchemaNode) { + valueNs = getValueNs(curSchemaNode, valNamespace, type); + propNode = propNode.addChild(name, ns, + SINGLE_INSTANCE_LEAF_NODE, + value, valueNs, curSchemaNode); + } else if (curSchemaNode instanceof LeafListSchemaNode) { + valueNs = getValueNs(curSchemaNode, valNamespace, type); + propNode = propNode.addChild(null, name, ns, + MULTI_INSTANCE_LEAF_NODE, value, + valueNs, curSchemaNode); + } else if (curSchemaNode instanceof ListSchemaNode) { + propNode = propNode.addChild(null, name, ns, MULTI_INSTANCE_NODE, + curSchemaNode); + } else { + propNode = propNode.addChild(name, ns, SINGLE_INSTANCE_NODE, + curSchemaNode); + } + } + + /** + * Returns the namespace of the value namespace in case of identity ref. + * + * @param schemaNode schema node + * @param valNs value name space + * @param nodeType node type + * @return namespace of value namespace + * @throws SvcLogicException when namespace resolution fails for identityref + */ + private Namespace getValueNs(SchemaNode schemaNode, String valNs, + NodeType nodeType) throws SvcLogicException { + Namespace ns = null; + if (valNs != null) { + TypeDefinition type; + if (schemaNode instanceof LeafSchemaNode) { + type = ((LeafSchemaNode) schemaNode).getType(); + } else { + type = ((LeafListSchemaNode) schemaNode).getType(); + } + TypeDefinition<?> baseType = resolveBaseTypeFrom(type); + if (baseType instanceof IdentityrefTypeDefinition) { + if (nodeType == null) { + ns = getResolvedNamespace(null, valNs, getSchemaCtx(), + propNode); + } else { + ns = getResolvedNamespace(valNs, null, getSchemaCtx(), + propNode); + } + } + } + return ns; + } + + /** + * Validates that the node type from the data format matches with that of + * the corresponding schema node. + * + * @param type node type from the abstract data format + * @throws SvcLogicException when the node type is wrong + */ + private void validateNodeType(NodeType type) throws SvcLogicException { + boolean verify; + switch (type) { + case SINGLE_INSTANCE_LEAF_NODE: + verify = curSchemaNode instanceof LeafSchemaNode; + break; + + case MULTI_INSTANCE_LEAF_NODE: + verify = curSchemaNode instanceof LeafListSchemaNode; + break; + + case MULTI_INSTANCE_NODE: + verify = curSchemaNode instanceof ListSchemaNode; + break; + + case SINGLE_INSTANCE_NODE: + verify = (!(curSchemaNode instanceof LeafSchemaNode) && + !(curSchemaNode instanceof LeafListSchemaNode) && + !(curSchemaNode instanceof ListSchemaNode)); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + type.toString())); + } + if (!verify) { + throw new SvcLogicException(format(DF_ERR, curSchemaNode + .getQName().getLocalName(), type.toString())); + } + } + + /** + * Returns true if the child schema is present with the name and + * namespace inside the current schema node, if present updates the + * current schema node; false otherwise. + * + * @param name name of the child schema node + * @param namespace namespace of the child schema node + * @return returns true if the child schema is available; false otherwise + */ + private boolean isChildPresent(String name, Namespace namespace) { + QName qname = QName.create(namespace.moduleNs(), + Revision.of(namespace.revision()), name); + SchemaNode childNode = null; + if (curSchemaNode instanceof DataSchemaNode) { + Deque<DataSchemaNode> dataSchema = findSchemaNodeByNameAndNamespace( + (DataSchemaNode) curSchemaNode, name, namespace.moduleNs()); + + if (dataSchema != null && !dataSchema.isEmpty()) { + childNode = dataSchema.pop(); + } + + if (dataSchema != null && !dataSchema.isEmpty()) { + childNode = findSchemaForChild(((ChoiceSchemaNode) childNode), + qname); + } + + } else { + childNode = findDataChildSchemaByQName(curSchemaNode, qname); + } + + if (childNode != null) { + curSchemaNode = childNode; + return true; + } + return false; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java new file mode 100644 index 000000000..0f03039e5 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java @@ -0,0 +1,233 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Collection; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.LeafNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeListener; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; + +import static com.google.common.base.Strings.repeat; +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.JSON_WRITE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; + +/** + * Representation of JSON implementation of properties node listener. + */ +public class PropertiesNodeJsonListener implements PropertiesNodeListener{ + + /** + * JSON writer to write the JSON data format. + */ + private JsonWriter jsonWriter; + + /** + * Writer to write the JSON. + */ + private Writer writer; + + /** + * Creates the properties node JSON listener by instantiating and + * indenting the writer. + */ + public PropertiesNodeJsonListener() { + writer = new StringWriter(); + jsonWriter = new JsonWriter(writer); + jsonWriter.setIndent(repeat(" ", 4)); + } + + @Override + public void start(PropertiesNode node) throws SvcLogicException { + try { + jsonWriter.beginObject(); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + @Override + public void end(PropertiesNode node) throws SvcLogicException { + try { + jsonWriter.endObject(); + jsonWriter.flush(); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + @Override + public void enterPropertiesNode(PropertiesNode node) + throws SvcLogicException { + String val; + String nodeName = getNodeName(node); + try { + switch (node.nodeType()) { + case SINGLE_INSTANCE_NODE: + jsonWriter.name(nodeName); + jsonWriter.beginObject(); + break; + + case MULTI_INSTANCE_NODE: + jsonWriter.beginObject(); + break; + + case SINGLE_INSTANCE_LEAF_NODE: + val = getValueWithNs((LeafNode) node); + jsonWriter.name(nodeName).value(val); + break; + + case MULTI_INSTANCE_HOLDER_NODE: + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + jsonWriter.name(nodeName); + jsonWriter.beginArray(); + break; + + case MULTI_INSTANCE_LEAF_NODE: + val = getValueWithNs((LeafNode) node); + jsonWriter.value(val); + break; + + case ANY_XML_NODE: + jsonWriter.name(nodeName); + val = ((LeafNode) node).value(); + try { + jsonWriter.jsonValue(val); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + + } + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + @Override + public void exitPropertiesNode(PropertiesNode node) throws SvcLogicException { + walkAugmentationNode(node); + try { + switch (node.nodeType()) { + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + jsonWriter.endObject(); + break; + + case MULTI_INSTANCE_HOLDER_NODE: + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + jsonWriter.endArray(); + break; + + case SINGLE_INSTANCE_LEAF_NODE: + case MULTI_INSTANCE_LEAF_NODE: + case ANY_XML_NODE: + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + /** + * Returns the writer. + * + * @return writer + */ + public Writer getWriter() { + return writer; + } + + /** + * Returns the abstract JSON node name to be used in JSON data format + * from the properties node. + * + * @param node properties node + * @return abstract JSON node + */ + private String getNodeName(PropertiesNode node) { + PropertiesNode parent = node.parent(); + if (parent instanceof RootNode || !parent.namespace().moduleName() + .equals(node.namespace().moduleName())) { + if (!parent.nonAppend()) { + return node.namespace().moduleName() + ":" + node.name(); + } + } + return node.name(); + } + + /** + * Returns the value of JSON leaf node with module name if required. + * + * @param node properties node + * @return value with namespace + */ + private String getValueWithNs(LeafNode node) { + Namespace valNs = node.valueNs(); + String modName = (valNs == null) ? null : valNs.moduleName(); + if (modName != null) { + return modName + ":" + node.value(); + } + return node.value(); + } + + /** + * Gets all the augmentation of the given node and walks through it. + * + * @param node properties node + * @throws SvcLogicException when walking the properties node fails + */ + private void walkAugmentationNode(PropertiesNode node) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> augChild = augToChild.getValue(); + if (!augChild.isEmpty()) { + DefaultPropertiesNodeWalker walker = new + DefaultPropertiesNodeWalker(); + for (PropertiesNode p : augChild) { + enterPropertiesNode(p); + walker.walkChildNode(this, p); + exitPropertiesNode(p); + } + } + } + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java new file mode 100644 index 000000000..f098195e4 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java @@ -0,0 +1,246 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Document; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.LeafNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeListener; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; + +import java.io.Writer; +import java.net.URI; +import java.util.Collection; +import java.util.Map; +import java.util.Stack; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.UTF_HEADER; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_PREFIX; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlWriter; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; + +/** + * Representation of XML implementation of properties node listener. + */ +public class PropertiesNodeXmlListener implements PropertiesNodeListener { + + /** + * XML data from the element. + */ + private String xmlData; + + /** + * Root element of the XML document. + */ + private Element rootElement; + + /** + * Writer to write the XML. + */ + private Writer writer; + + /** + * XML element stack to store the elements. + */ + private final Stack<Element> elementStack = new Stack<>(); + + /** + * Creates the properties node XML listener. + */ + public PropertiesNodeXmlListener() { + } + + @Override + public void start(PropertiesNode node) { + rootElement = addElement(null, node); + elementStack.push(rootElement); + } + + @Override + public void end(PropertiesNode node) throws SvcLogicException { + xmlData = rootElement.asXML(); + xmlData = UTF_HEADER + xmlData; + writer = getXmlWriter(xmlData, "4"); + } + + @Override + public void enterPropertiesNode(PropertiesNode node) + throws SvcLogicException { + Element element = null; + String ns = getNodeNamespace(node); + switch (node.nodeType()) { + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + case MULTI_INSTANCE_HOLDER_NODE: + break; + + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + element = addElement(ns, node); + break; + + case MULTI_INSTANCE_LEAF_NODE: + case SINGLE_INSTANCE_LEAF_NODE: + element = addElement(ns, node); + setValueWithNs(element, (LeafNode) node); + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + if (element != null) { + elementStack.push(element); + } + } + + @Override + public void exitPropertiesNode(PropertiesNode node) + throws SvcLogicException { + walkAugmentationNode(node); + switch (node.nodeType()) { + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + case MULTI_INSTANCE_HOLDER_NODE: + break; + + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + case MULTI_INSTANCE_LEAF_NODE: + case SINGLE_INSTANCE_LEAF_NODE: + if (!elementStack.isEmpty()) { + elementStack.pop(); + } + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + } + + /** + * Returns the writer. + * + * @return writer + */ + public Writer getWriter() { + return writer; + } + + /** + * Adds an XML element to the stack with namespace if present. If the + * stack is empty it creates new document and adds element else adds to + * the parent element. + * + * @param ns namespace of the element + * @param node properties node + * @return new added element + */ + private Element addElement(String ns, PropertiesNode node) { + Element element; + if (elementStack.isEmpty()) { + Document doc = DocumentHelper.createDocument(); + if (ns != null) { + element = doc.addElement(node.name(), ns); + } else { + element = doc.addElement(node.name()); + } + } else { + element = elementStack.peek(); + if (ns != null) { + element = element.addElement(node.name(), ns); + } else { + element = element.addElement(node.name()); + } + } + + return element; + } + + /** + * Returns the abstract XML namespace to be used in XML data format from + * the properties node. + * + * @param node properties node + * @return abstract XML namespace + */ + private String getNodeNamespace(PropertiesNode node) { + PropertiesNode parent = node.parent(); + if (parent.nodeType() == MULTI_INSTANCE_HOLDER_NODE || + parent.nodeType() == MULTI_INSTANCE_LEAF_HOLDER_NODE) { + parent = parent.parent(); + } + if (parent instanceof RootNode || ! parent.namespace().moduleName() + .equals(node.namespace().moduleName())) { + return node.namespace().moduleNs().toString(); + } + return null; + } + + /** + * Sets the value to the element for a leaf node and adds the value + * namespace if required. + * + * @param element XML element + * @param node leaf properties node + */ + private void setValueWithNs(Element element, LeafNode node) { + Namespace valNs = node.valueNs(); + URI modNs = (valNs == null) ? null : valNs.moduleNs(); + String val = node.value(); + if (modNs != null) { + element.addNamespace(XML_PREFIX, modNs.toString()); + element.setText(XML_PREFIX + ":" + val); + } else { + element.setText(val); + } + } + + /** + * Gets all the augmentation of the given node and walks through it. + * + * @param node properties node + * @throws SvcLogicException when walking the properties node fails + */ + private void walkAugmentationNode(PropertiesNode node) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> augChild = augToChild.getValue(); + if (!augChild.isEmpty()) { + DefaultPropertiesNodeWalker walker = new + DefaultPropertiesNodeWalker(); + for (PropertiesNode p : augChild) { + enterPropertiesNode(p); + walker.walkChildNode(this, p); + exitPropertiesNode(p); + } + } + } + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java new file mode 100644 index 000000000..db9befb21 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java @@ -0,0 +1,116 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; + +/** + * Abstraction of an entity which helps the data format serializers to obtain + * schema context details and to build properties from data. + * + * @param <T> type of schema node + * @param <P> type of schema context + */ +public abstract class SerializerHelper<T, P> { + + /** + * Schema node of the last element in the URI. + */ + protected T schemaNode; + + /** + * Root schema context. + */ + protected P schemaCtx; + + /** + * Root URI. + */ + protected String rootUri; + + /** + * Creates an instance of the serializer helper with the schema node, + * schema context and the URI. + * + * @param t schema node + * @param p schema context + * @param u root URI + */ + protected SerializerHelper(T t, P p, String u) { + schemaNode = t; + schemaCtx = p; + rootUri = u; + } + + /** + * Returns schema node of the last element in the URI. + * + * @return schema node + */ + protected abstract T getSchemaNode(); + + /** + * Returns the root schema context. + * + * @return schema context + */ + protected abstract P getSchemaCtx(); + + /** + * Returns the current schema context node. + * + * @return current schema context node + */ + protected abstract T getCurSchema(); + + /** + * Adds a node to the properties node tree. + * + * @param name name of the node + * @param nameSpace name space of the node, it can be either module + * name or namespace; null indicates parent namespace + * @param value value of the node; applicable for leaf/leaf-list node + * @param valNameSpace value namespace for identityref, could be module + * name or namespace + * @param type type of node if known like in case of JSON + * @throws SvcLogicException when adding node fails + */ + protected abstract void addNode(String name, String nameSpace, String value, + String valNameSpace, NodeType type) + throws SvcLogicException; + + /** + * Exits the node, in case if it's leaf node then it adds to the properties + * map. + * + * @throws SvcLogicException when properties node tree is improper + */ + protected abstract void exitNode() throws SvcLogicException; + + /** + * Returns the built properties corresponding to the data. + * + * @return properties node. + */ + protected abstract PropertiesNode getPropertiesNode(); +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java new file mode 100644 index 000000000..784e7af1f --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of an entity which provides call back methods, which in turn + * are called by XML walker while walking the XML tree. This interface needs + * to be implemented by protocol implementing listener based call while doing + * XML walk. + */ +public interface XmlListener extends Listener { + + /** + * Callback invoked during a node entry. All the related information + * about the node can be obtained from the element. + * + * @param element current XML element + * @param nodeType node type of the element + * @throws SvcLogicException when node type is of wrong format + */ + void enterXmlElement(Element element, XmlNodeType nodeType) + throws SvcLogicException; + + /** + * Callback invoked during a node exit. All the related information about + * the node can be obtained from the element. + * + * @param element current xml element. + * @throws SvcLogicException when XML node exit doesn't happen + */ + void exitXmlElement(Element element) throws SvcLogicException; +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlNodeType.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlNodeType.java new file mode 100644 index 000000000..7a6db3c86 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlNodeType.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Represents the XML node type. + */ +public enum XmlNodeType { + + /** + * Object XML node type. + */ + OBJECT_NODE, + + /** + * Text XML node type. + */ + TEXT_NODE +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java new file mode 100644 index 000000000..f3c6723e1 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeWalker; + +import java.io.Writer; +import java.util.List; +import java.util.Map; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormat.XML; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_LIS_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_TREE_ERR; + +/** + * Representation of XML serializer which encodes properties to XML and + * decodes properties from XML with the data format serializer. + */ +public class XmlSerializer extends DataFormatSerializer { + + /** + * Creates an instance of XML serializer. + * + * @param serializerContext data format serializer context + */ + protected XmlSerializer(DataFormatSerializerContext serializerContext) { + super(XML, serializerContext); + } + + @Override + public String encode(Map<String, String> param, + Map<String, List<Annotation>> annotations) + throws SvcLogicException { + PropertiesNode propNode = serializerContext().getPropNodeSerializer() + .encode(param); + PropertiesNodeWalker nodeWalker = new DefaultPropertiesNodeWalker<>(); + PropertiesNodeXmlListener xmlListener = new PropertiesNodeXmlListener(); + nodeWalker.walk(xmlListener, propNode); + Writer writer = xmlListener.getWriter(); + return removeRootNode(writer.toString(), propNode.name()); + } + + @Override + public Map<String, String> decode(String dataFormatBody) + throws SvcLogicException { + if (!(serializerContext().listener() instanceof XmlListener)) { + throw new SvcLogicException(XML_LIS_ERR); + } + + XmlListener listener = (XmlListener) serializerContext().listener(); + XmlWalker walker = new DefaultXmlWalker(); + Document document; + + try { + document = DocumentHelper.parseText(dataFormatBody); + } catch (DocumentException e) { + throw new SvcLogicException(XML_TREE_ERR, e); + } + walker.walk(listener, document.getRootElement()); + + return serializerContext().getPropNodeSerializer().decode( + listener.serializerHelper().getPropertiesNode()); + } + + /** + * Removes root node from the XML data format message and makes the + * string to be pretty print. + * + * @param xml XML data format message + * @param rootName root node name + * @return pretty print format XML message + */ + private static String removeRootNode(String xml, String rootName) { + xml = xml.replace("\n<" + rootName + ">", "\n"); + xml = xml.replace("</" + rootName + ">" + "\n", ""); + xml = xml.replaceAll("\n" + " ", "\n"); + xml = xml.replaceFirst("\n", ""); + return xml; + } +}
\ No newline at end of file diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java new file mode 100644 index 000000000..3835faa7e --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of an entity which provides interface for XML walk. This + * interface serves as a common tool for anyone who needs to parse the XML + * node with depth-first algorithm. + */ +public interface XmlWalker { + + /** + * Walks the XML data tree. Protocols implement XML listener service and + * walks the XML tree with input as implemented object. XML walker + * provides call back to the implemented methods. + * + * @param listener XML listener implemented by the protocol + * @param xmlElement root element of the XML data tree + * @throws SvcLogicException when walking the XML node fails + */ + void walk(XmlListener listener, Element xmlElement) throws + SvcLogicException; +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/YangParameters.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/YangParameters.java new file mode 100644 index 000000000..8eb3fb6e8 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/YangParameters.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.plugins.restapicall.Parameters; + +/** + * Representation of the YANG parameters for the restconf api call node. + */ +public class YangParameters extends Parameters { + /** + * Directory path of the YANG file. + */ + public String dirPath; + + /** + * Creates an instance of the YANG parameters. + */ + public YangParameters() { + super(); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DataNodeChild.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DataNodeChild.java new file mode 100644 index 000000000..7be54690a --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DataNodeChild.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of entity representing child's to data node. + */ +public interface DataNodeChild extends NodeChild { +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java new file mode 100644 index 000000000..2fa00bfb7 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.COLON; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.UNDERSCORE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; + +/** + * Represents implementation of PropertiesNodeListener. + */ +public class DefaultPropertiesNodeListener implements PropertiesNodeListener { + + private Map<String, String> params = new HashMap<>(); + + @Override + public void start(PropertiesNode node) { + // do nothing + } + + @Override + public void end(PropertiesNode node) throws SvcLogicException { + exitPropertiesNode(node); + } + + @Override + public void enterPropertiesNode(PropertiesNode node) { + /* + * Only if it is leaf node or leaf-list node, + * then create a property entry and add to map + */ + if (node.nodeType() == SINGLE_INSTANCE_LEAF_NODE + || node.nodeType() == MULTI_INSTANCE_LEAF_NODE) { + String val = ((LeafNode) node).value(); + if (((LeafNode) node).valueNs() != null) { + val = ((LeafNode) node).valueNs().moduleName() + COLON + val; + } + String uri = node.uri().replaceAll(COLON, UNDERSCORE); + params.put(uri, val); + } + } + + @Override + public void exitPropertiesNode(PropertiesNode node) throws + SvcLogicException { + if (!node.augmentations().isEmpty()) { + for (Map.Entry<Object, Collection<PropertiesNode>> augmentationTochild + : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> childsFromAugmentations = augmentationTochild + .getValue(); + if (!childsFromAugmentations.isEmpty()) { + PropertiesNodeWalker walker = new DefaultPropertiesNodeWalker<>(); + for (PropertiesNode pNode : childsFromAugmentations) { + enterPropertiesNode(pNode); + walker.walk(this, pNode); + exitPropertiesNode(pNode); + } + } + } + } + } + + /** + * Returns properties. + * + * @return properties + */ + public Map<String, String> params() { + return params; + } + + /** + * Sets properties. + * + * @param params properties + */ + public void params(Map<String, String> params) { + this.params = params; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java new file mode 100644 index 000000000..5034530d5 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.Collection; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Implementation of properties node walker which helps in forming a new tree from properties node. + * + * @param <T> node child of properties node. + */ +public class DefaultPropertiesNodeWalker<T extends NodeChild> implements PropertiesNodeWalker { + + @Override + public void walk(PropertiesNodeListener listener, + PropertiesNode propertiesNode) throws SvcLogicException { + listener.start(propertiesNode); + walkChildNode(listener, propertiesNode); + listener.end(propertiesNode); + } + + /** + * Walks the children node from the parent node. + * + * @param listener properties node listener + * @param propertiesNode properties node + * @throws SvcLogicException when properties node walking fails + */ + public void walkChildNode(PropertiesNodeListener listener, + PropertiesNode propertiesNode) + throws SvcLogicException { + Map<String, T> children = getChildren(propertiesNode); + if (children != null) { + for (Map.Entry<String, T> entry : children.entrySet()) { + PropertiesNode node = ((PropertiesNode) entry.getValue()); + listener.enterPropertiesNode(node); + walkChildNode(listener, node); + listener.exitPropertiesNode(node); + } + } + if (propertiesNode instanceof RootNode) { + processAugments(propertiesNode, listener); + } + } + + /** + * Processes the augments present in the root node. + * + * @param node root node + * @param listener properties node listener + * @throws SvcLogicException when augment node walking fails + */ + private void processAugments(PropertiesNode node, + PropertiesNodeListener listener) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> child = augToChild.getValue(); + if (!child.isEmpty()) { + for (PropertiesNode p : child) { + listener.enterPropertiesNode(p); + walkChildNode(listener, p); + listener.exitPropertiesNode(p); + } + } + } + } + + /** + * Returns the children node according to the property node type. + * + * @param value property node + * @return property node children + */ + private Map<String,T> getChildren(PropertiesNode value) { + if (value instanceof RootNode) { + return ((RootNode) value).children(); + } + switch (value.nodeType()) { + case SINGLE_INSTANCE_NODE: + return ((InnerNode) value).children(); + case MULTI_INSTANCE_HOLDER_NODE: + return ((Map<String, T>) ((ListHolderNode) value).children()); + case MULTI_INSTANCE_NODE: + return ((Map<String, T>) ((MultiInstanceNode) value) + .children()); + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + return ((Map<String, T>) ((LeafListHolderNode) value) + .children()); + case SINGLE_INSTANCE_LEAF_NODE: + case MULTI_INSTANCE_LEAF_NODE: + case ANY_XML_NODE: + return null; + default: + throw new IllegalArgumentException("No more types allowed"); + } + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/HolderNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/HolderNode.java new file mode 100644 index 000000000..52bec3412 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/HolderNode.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.HashMap; +import java.util.Map; + +/** + * Abstraction of an entity that represents holder node to multi instance node + * in properties data tree. + * + * @param <T> type of child + */ +public abstract class HolderNode<T extends NodeChild> extends PropertiesNode { + + private Map<String, T> children = new HashMap<>(); + + protected HolderNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, + NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + /** + * Returns children. + * + * @return children + */ + public Map<String, T> children() { + return children; + } + + /** + * Returns child based on index. + * + * @return child based on index + */ + public T child(String index) { + return children.get(index); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/InnerNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/InnerNode.java new file mode 100644 index 000000000..1cf99b2d4 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/InnerNode.java @@ -0,0 +1,215 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.addToAugmentations; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.createNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getAugmentationNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getUri; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.isNamespaceAsParent; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.resolveName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findCorrespondingAugment; + +/** + * Abstraction of an entity that represents an inner node to properties data + * tree. + * + * @param <T> type of child + */ +public abstract class InnerNode<T extends NodeChild> extends PropertiesNode { + + private Map<String, T> children = new HashMap<String, T>(); + + protected InnerNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + /** + * Returns children. + * + * @return children + */ + public Map<String, T> children() { + return children; + } + + /** + * Sets children. + * + * @param children child nodes + */ + public void children(Map<String, T> children) { + this.children = children; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + PropertiesNode node = ((PropertiesNode) children.get(name)); + if (node != null) { + return node; + } + + // get augment schema, if it is augmented node + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, name); + } + + // create node based on type + if (node == null) { + String uri = getUri(this, name, namespace); + node = createNode(name, namespace, uri, this, appInfo, type); + } + + // If namespace is not same as parent then it is augmented node + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + LeafNode node = ((LeafNode) children.get(name)); + if (node != null) { + return node; + } + + AugmentationSchemaNode augSchema = null; + String uri = getUri(this, name, namespace); + node = new LeafNode(name, namespace, uri, this, + appInfo, type, value); + + if (type != NodeType.ANY_XML_NODE) { + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment( + ((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + } + node.valueNs(valueNs); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + Object appInfo) throws SvcLogicException { + String localname = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localname)); + + if (node == null) { + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localname); + } + + if (node == null) { + String uri = getUri(this, name, namespace); + node = new ListHolderNode(localname, namespace, uri, + this, appInfo, MULTI_INSTANCE_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localname, ((T) node)); + } + + node = node.addChild(index, localname, namespace, type, appInfo); + } else if (node instanceof ListHolderNode) { + ListHolderChild child = ((ListHolderNode) node).child(index); + node = (child != null ? ((MultiInstanceNode) child) : + node.addChild(index, localname, namespace, type, appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + String localName = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localName)); + + if (node == null) { + + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localName); + } + + if (node == null) { + String uri = getUri(this, name, namespace); + node = new LeafListHolderNode(localName, namespace, uri, this, + appInfo, MULTI_INSTANCE_LEAF_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localName, ((T) node)); + } + + node = node.addChild(index, localName, namespace, type, value, valueNs, appInfo); + } else if (node instanceof LeafListHolderNode) { + LeafNode child = ((LeafNode) ((HolderNode) node).child(index)); + node = (child != null ? child : node.addChild(index, localName, + namespace, type, + value, valueNs, + appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderChild.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderChild.java new file mode 100644 index 000000000..e43249a3d --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderChild.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of entity representing child's to leaf list holder. + */ +public interface LeafListHolderChild extends NodeChild { + +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderNode.java new file mode 100644 index 000000000..46ab5bb63 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderNode.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Representation of leaf list holder node which will hold multi instance leaf + * node in properties data tree. + */ +public class LeafListHolderNode extends HolderNode<LeafListHolderChild> implements DataNodeChild { + + private static final String node = " holder node"; + + /** + * Creates an instance of LeafListHolderNode. + * + * @param name name of the leaf-list node + * @param namespace namespace of the leaf-list node + * @param uri uri of the leaf-list node + * @param parent parent node of the leaf-list + * @param appInfo application info + * @param nodeType node type + */ + public LeafListHolderNode(String name, Namespace namespace, + String uri, PropertiesNode parent, + Object appInfo, NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf cannot be child of leaf-list" + + node); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Container cannot be child of leaf-list" + + node); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("List cannot be child of leaf-list" + + node); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + LeafNode node = ((LeafNode) children().get(index)); + if (index == null) { + index = String.valueOf(children().size()); + } + String uri = this.uri() + "[" + index + "]"; + node = (node != null) ? node : new LeafNode(name, namespace, uri, + this, appInfo, type, value); + node.valueNs(valueNs); + children().put(index, node); + return node; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafNode.java new file mode 100644 index 000000000..041175ca7 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafNode.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Representation of leaf node in properties data tree. + */ +public class LeafNode extends PropertiesNode implements LeafListHolderChild, DataNodeChild { + + private String value; + private Namespace valueNs; + private static final String svcLogicException = "Leaf cannot hold child nodes"; + + /** + * Creates an instance of leaf node. + * + * @param name name of the leaf node + * @param namespace namespace of the leaf node + * @param uri uri of the leaf node + * @param parent parent of the leaf node + * @param appInfo application info + * @param nodeType node type + * @param value value of the leaf + */ + public LeafNode(String name, Namespace namespace, + String uri, PropertiesNode parent, + Object appInfo, NodeType nodeType, + String value) { + super(name, namespace, uri, parent, appInfo, nodeType); + this.value = value; + } + + /** + * Returns value of the leaf. + * + * @return value of the leaf + */ + public String value() { + return value; + } + + /** + * Sets value of the leaf. + * + * @param value value of the leaf + */ + public void value(String value) { + this.value = value; + } + + /** + * Returns value namespace. + * + * @return value namespace + */ + public Namespace valueNs() { + return valueNs; + } + + /** + * Sets value namespace. + * + * @param valueNs value namespace + */ + public void valueNs(Namespace valueNs) { + this.valueNs = valueNs; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException(svcLogicException); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException(svcLogicException); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException(svcLogicException); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf cannot hold child nodes"); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderChild.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderChild.java new file mode 100644 index 000000000..ec9cc2a0f --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderChild.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of entity representing child's to list holder. + */ +public interface ListHolderChild extends NodeChild { + +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderNode.java new file mode 100644 index 000000000..ba9da54cf --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderNode.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Representation of list holder node which will hold multi instance node in + * properties data tree. + */ +public class ListHolderNode extends HolderNode<ListHolderChild> implements DataNodeChild { + + protected ListHolderNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf cannot be child of list holder node"); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Container cannot be child of list holder node"); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + Object appInfo) throws SvcLogicException { + MultiInstanceNode node = ((MultiInstanceNode) children().get(index)); + if (index == null) { + index = String.valueOf(children().size()); + } + String uri = this.uri() + "[" + index + "]"; + node = (node != null) ? node : new MultiInstanceNode(name, namespace, uri, + this, appInfo, type); + children().put(index, node); + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf-list cannot be child of list holder node"); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java new file mode 100644 index 000000000..8a6e75668 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java @@ -0,0 +1,227 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.DOT_REGEX; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.SLASH; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getChildSchemaNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getIndex; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getListName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getNamespace; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getNodeType; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getParsedValue; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getProcessedPath; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getValueNamespace; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.resolveName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.ANY_XML_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; + +/** + * Representation of mdsal based properties node serializer implementation. + */ +public class MdsalPropertiesNodeSerializer extends PropertiesNodeSerializer<SchemaNode, SchemaContext> { + + private static final Logger log = LoggerFactory.getLogger( + MdsalPropertiesNodeSerializer.class); + private SchemaNode curSchema; + private PropertiesNode node; + + /** + * Creates the properties node serializer. + * + * @param schemaNode schema node. + * @param schemaCtx schema context + * @param uri URL of the request + */ + public MdsalPropertiesNodeSerializer(SchemaNode schemaNode, + SchemaContext schemaCtx, String uri) { + super(schemaNode, schemaCtx, uri); + } + + @Override + public PropertiesNode encode(Map<String, String> paramMap) throws SvcLogicException { + curSchema = schemaNode(); + String nodeInUri[] = uri().split("\\/"); + String lastNodeName = nodeInUri[nodeInUri.length - 1]; + String rootUri = uri().replaceAll("\\/", "\\."); + node = createRootNode(lastNodeName, rootUri); + + paramMap = convertToValidParam(paramMap); + + updateModNameReq(paramMap, rootUri); + + for (Map.Entry<String, String> entry : paramMap.entrySet()) { + String[] names = entry.getKey().split("\\."); + for (int i = 0; i < names.length; i++) { + if (i < nodeInUri.length) { + if (!(nodeInUri[i].equals(names[i]))) { + break; + } + } else { + createPropertyNode(i, names.length, names[i], + entry.getValue()); + } + } + } + return node; + } + + private void updateModNameReq(Map<String, String> paramMap, + String rootUri) { + String isReqStr = rootUri + "." + "isNonAppend"; + String val = paramMap.get(isReqStr); + if (val != null && val.equals("true")) { + node.nonAppend(true); + } + } + + /** + * Converts all the params in the svc logic context into a valid param by + * replacing the underscore in module name to colon at necessary places. + * + * @param paramMap list of invalid parameters + * @return list of partially valid parameters + */ + private Map<String, String> convertToValidParam(Map<String, String> paramMap) { + Map<String, String> fixedParams = new HashMap<>(); + for(Map.Entry<String, String> entry : paramMap.entrySet()) { + String key = entry.getKey().replaceAll(DOT_REGEX, SLASH); + try { + SchemaPathHolder fixedUrl = getProcessedPath(key, schemaCtx()); + String fixedUri = fixedUrl.getUri().replaceAll( + SLASH, DOT_REGEX); + fixedParams.put(fixedUri, entry.getValue()); + } catch (IllegalArgumentException | RestconfDocumentedException + | NullPointerException e) { + log.info("Exception while processing properties by replacing " + + "underscore with colon. Process the properties as it is." + e); + fixedParams.put(entry.getKey(), entry.getValue()); + } + } + return fixedParams; + } + + @Override + public Map<String, String> decode(PropertiesNode propertiesNode) + throws SvcLogicException { + PropertiesNodeWalker walker = new DefaultPropertiesNodeWalker<>(); + DefaultPropertiesNodeListener listener = new DefaultPropertiesNodeListener(); + walker.walk(listener, propertiesNode); + return listener.params(); + } + + private RootNode createRootNode(String lastNodeName, String rootUri) { + Module m = SchemaContextUtil.findParentModule(schemaCtx(), curSchema); + Namespace ns = new Namespace(m.getName(), m.getNamespace(), + getRevision(m.getRevision())); + return new RootNode(lastNodeName, ns, schemaNode(), rootUri); + } + + private void createPropertyNode(int index, int length, String name, + String value) throws SvcLogicException { + + Namespace ns = getNamespace(getListName(name), schemaCtx(), + node, curSchema); + String localName = resolveName(ns, name); + SchemaNode schema = getChildSchemaNode(curSchema, localName, ns); + if (schema == null) { + return; + } + + switch (getNodeType(index, length, name, schema)) { + case SINGLE_INSTANCE_NODE: + node = node.addChild(localName, ns, + SINGLE_INSTANCE_NODE, schema); + curSchema = schema; + break; + + case MULTI_INSTANCE_NODE: + node = node.addChild(getIndex(name), localName, ns, + MULTI_INSTANCE_NODE, schema); + curSchema = schema; + break; + + case SINGLE_INSTANCE_LEAF_NODE: + addLeafNode(value, SINGLE_INSTANCE_LEAF_NODE, localName, + ns, schema, name); + break; + + case MULTI_INSTANCE_LEAF_NODE: + addLeafNode(value, MULTI_INSTANCE_LEAF_NODE, localName, + ns, schema, name); + break; + + case ANY_XML_NODE: + node = node.addChild(localName, ns, ANY_XML_NODE, + value, null, schema); + node = node.endNode(); + curSchema = ((SchemaNode) node.appInfo()); + break; + + default: + throw new SvcLogicException("Invalid node type"); + } + } + + /** + * Adds leaf property node to the current node. + * + * @param value value of the leaf node + * @param type single instance or multi instance leaf node + * @param localName name of the leaf node + * @param ns namespace of the leaf node + * @param schema schema of the leaf node + * @param name name of the leaf in properties + * @throws SvcLogicException exception while adding leaf node + */ + private void addLeafNode(String value, NodeType type, + String localName, Namespace ns, + SchemaNode schema, String name) throws SvcLogicException { + Namespace valNs = getValueNamespace(value, schemaCtx()); + value = getParsedValue(valNs, value); + if (SINGLE_INSTANCE_LEAF_NODE == type) { + node = node.addChild(localName, ns, SINGLE_INSTANCE_LEAF_NODE, + value, valNs, schema); + } else { + node = node.addChild(getIndex(name), localName, ns, + MULTI_INSTANCE_LEAF_NODE, value, + valNs, schema); + } + node = node.endNode(); + curSchema = ((SchemaNode) node.appInfo()); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeUtils.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeUtils.java new file mode 100644 index 000000000..e6fa064f5 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeUtils.java @@ -0,0 +1,578 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.Optional; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; +import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils; +import org.opendaylight.yangtools.yang.data.util.ParserStreamUtils; +import org.opendaylight.yangtools.yang.data.util.codec.IdentityCodecUtil; +import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; +import static java.util.regex.Pattern.quote; +import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier.toInstanceIdentifier; + +/** + * Represents utilities for properties node tree. + */ +public final class MdsalPropertiesNodeUtils { + + static final String COLON = ":"; + + static final String UNDERSCORE = "_"; + + static final String SLASH = "/"; + + static final String DOT_REGEX = "\\."; + + private static final String INFO_MSG = "The %s formed is currently not" + + " valid"; + + private static final String EXC_MSG = "Unable to form a formatted path"; + + /** + * Logger for the Mdsal properties util class. + */ + private static final Logger log = LoggerFactory.getLogger( + MdsalPropertiesNodeUtils.class); + + private MdsalPropertiesNodeUtils() { + } + + /** + * Returns the index from multi instance property name. + * + * @param name name of the property + * @return index from multi instance property name + */ + public static String getIndex(String name) { + return name.substring(name.indexOf("[") + 1, + name.indexOf("]")); + } + + /** + * Returns the multi instance property name. + * + * @param name name of the property + * @return the multi instance property name + */ + public static String getListName(String name) { + String[] s = name.split("\\["); + return s[0]; + } + + /** + * Returns true if property is multi instance. + * + * @param name name of the property + * @return true if property is multi instance + */ + public static boolean isListEntry(String name) { + String s[] = name.split("\\["); + return s.length > 1; + } + + /** + * Returns name of the property after pruning namespace and + * index if the property is multi instance. + * + * @param name name of the property + * @return name of the property + */ + static String resolveName(String name) { + String localName = getListName(name); + final int lastIndexOfColon = localName.lastIndexOf(":"); + if (lastIndexOfColon != -1) { + localName = localName.substring(lastIndexOfColon + 1); + } + return localName; + } + + /** + * Returns name of the property after pruning namespace and index if the + * property is multi instance by knowing the module name from namespace. + * + * @param ns namespace + * @param name name of the node + * @return resolved name + */ + static String resolveName(Namespace ns, String name) { + String localName = getListName(name); + String modName = ns.moduleName(); + if ((localName.contains(COLON) || localName.contains(UNDERSCORE)) + && localName.startsWith(modName)) { + localName = localName.substring(modName.length()+1); + } + return localName; + } + + /** + * Adds current node to parent's augmentation map. + * + * @param augSchema augment schema + * @param parent parent property node + * @param curNode current property node + */ + public static void addToAugmentations(AugmentationSchemaNode augSchema, + PropertiesNode parent, + PropertiesNode curNode) { + Collection<PropertiesNode> childsFromAugmentation = parent + .augmentations().get(augSchema); + if (!childsFromAugmentation.isEmpty()) { + for (PropertiesNode pNode : childsFromAugmentation) { + if (pNode.name().equals(curNode.name())) { + return; + } + } + } + parent.augmentations().put(augSchema, curNode); + } + + + /** + * Returns augmented properties node if it is already + * added in properties tree. + * + * @param augSchema augmented schema node + * @param parent parent properties node + * @param name name of the properties + * @return augmented properties node if it is already added + */ + public static PropertiesNode getAugmentationNode( + AugmentationSchemaNode augSchema, + PropertiesNode parent, String name) { + if (augSchema == null) { + return null; + } + + Collection<PropertiesNode> childsFromAugmentation = parent + .augmentations().get(augSchema); + if (!childsFromAugmentation.isEmpty()) { + for (PropertiesNode pNode : childsFromAugmentation) { + if (pNode.name().equals(name)) { + return pNode; + } + } + } + + return null; + } + + /** + * Creates uri with specified name and namespace. + * + * @param parent parent properties node + * @param name name of the node + * @param ns namespace of the node + * @return uri with specified name and namespace + */ + public static String getUri(PropertiesNode parent, String name, + Namespace ns) { + String uri = name; + if (!(parent.namespace().moduleNs().equals(ns.moduleNs()))) { + uri = ns.moduleName() + ":" + name; + } + return parent.uri() + "." + uri; + } + + /** + * Creates new properties with specified parameters. + * + * @param name name of the properties node + * @param namespace namespace of the properties node + * @param uri uri of the properties node + * @param parent parent node + * @param appInfo application info + * @param type node type + * @return new properties node + * @throws SvcLogicException exception while creating properties node + */ + public static PropertiesNode createNode(String name, Namespace namespace, + String uri, PropertiesNode parent, + Object appInfo, NodeType type) + throws SvcLogicException { + switch (type) { + case SINGLE_INSTANCE_NODE: + return new SingleInstanceNode(name, namespace, uri, parent, appInfo, type); + case MULTI_INSTANCE_HOLDER_NODE: + return new ListHolderNode(name, namespace, uri, parent, appInfo, type); + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + return new LeafListHolderNode(name, namespace, uri, parent, appInfo, type); + default: + throw new SvcLogicException("Invalid node type " + type); + } + } + + /** + * Returns true if namespace is same as parent's namespace. + * + * @param parent parent property node + * @param curNode current property node + * @return true if namespace is same as parent namespace + */ + public static boolean isNamespaceAsParent(PropertiesNode parent, + PropertiesNode curNode) { + return parent.namespace().moduleNs().equals(curNode.namespace().moduleNs()); + } + + /** + * Returns the schema path holder with a formatted url and the instance + * identifier context from a given uri or the parameters from svc logic + * context. + * + * @param uri unformatted uri or parameter + * @param context schema context + * @return schema path holder + */ + public static SchemaPathHolder getProcessedPath(String uri, + SchemaContext context) { + + String uri1 = uri.replaceAll(UNDERSCORE, COLON); + try { + InstanceIdentifierContext<?> id = toInstanceIdentifier( + uri1, context, null); + return new SchemaPathHolder(id, uri1); + } catch (IllegalArgumentException | RestconfDocumentedException + | NullPointerException e) { + log.info("Exception while converting uri to instance identifier" + + " context. Process each node in uri to get instance identifier" + + " context " + e); + return processNodesAndAppendPath(uri, context); + } + } + + /** + * Processes the nodes in the given uri and finds instance identifier + * context till it reaches the last node in uri. If its not able to find + * schema for the path, it appends the suffix part and puts it back in + * the param list. + * + * @param uri uri with underscore + * @param context schema context + * @return schema and path holder + */ + private static SchemaPathHolder processNodesAndAppendPath(String uri, + SchemaContext context) { + + String actPath = ""; + SchemaPathHolder id = new SchemaPathHolder(null, ""); + String[] uriParts = uri.split(SLASH); + String sec = ""; + if (uri.contains(UNDERSCORE)) { + sec = uri.substring(uriParts[0].length()+1); + } + for (int i = 0; i<uriParts.length; i++) { + + try { + id = processIdentifier(uriParts[i], context, actPath); + } catch (IllegalArgumentException e) { + log.info(format(EXC_MSG, e)); + id.setUri(actPath+ uriParts[i] + sec); + return id; + } + + actPath = actPath + id.getUri() + SLASH; + if (sec.startsWith(SLASH)) { + sec = sec.replaceFirst(SLASH, ""); + } + if (i+1 < uriParts.length) { + sec = sec.replaceFirst(quote(uriParts[i + 1]), ""); + } + } + id.setUri(actPath.substring(0,actPath.length() - 1)); + return id; + } + + /** + * Processes the schema and path holder for a given node in the path. It + * figures if the path is valid by replacing underscore in the node + * consecutively, till it finds the proper schema for the node. + * + * @param node node in the path + * @param context schema context + * @param prefix prefix for the node in the path + * @return schema and path holder + */ + private static SchemaPathHolder processIdentifier(String node, + SchemaContext context, + String prefix) { + + String[] values = node.split(UNDERSCORE); + String val = values[0]; + StringBuilder firstHalf = new StringBuilder(); + String secondHalf = ""; + if (node.contains(UNDERSCORE)) { + secondHalf = node.substring(values[0].length()+1); + } + InstanceIdentifierContext<?> id; + for (int i = 0; i< values.length-1; i++) { + val = values[i]; + val = firstHalf + val + COLON + secondHalf; + try { + id = toInstanceIdentifier(prefix + val, context, null); + return new SchemaPathHolder(id, val); + } catch (IllegalArgumentException | RestconfDocumentedException | + NullPointerException e) { + log.info(format(INFO_MSG, val, e)); + } + firstHalf.append(values[i]).append(UNDERSCORE); + secondHalf = secondHalf.replaceFirst( + values[i + 1] + UNDERSCORE,""); + } + val = val.replace(COLON,UNDERSCORE); + try { + id = toInstanceIdentifier(prefix + val, context, null); + return new SchemaPathHolder(id, val); + } catch (IllegalArgumentException | RestconfDocumentedException | + NullPointerException e1) { + throw new IllegalArgumentException(EXC_MSG, e1); + } + } + + /** + * Returns the namespace of the given node name. If the node name is + * separated by colon, the it splits with colon and forms the namespace. + * If the node name is formed with underscore, then it splits the node + * name consecutively to figure out the proper module name. + * + * @param childName node name + * @param ctx schema context + * @param parent parent properties node + * @param curSchema current schema + * @return namespace of the given node + */ + static Namespace getNamespace(String childName, SchemaContext ctx, + PropertiesNode parent, SchemaNode curSchema) { + + Namespace parentNs = parent.namespace(); + Namespace ns = new Namespace(parentNs.moduleName(), + parentNs.moduleNs(), parentNs.revision()); + int lastIndexOfColon = childName.lastIndexOf(COLON); + if (lastIndexOfColon != -1) { + String moduleName = childName.substring(0, lastIndexOfColon); + childName = childName.substring(lastIndexOfColon+1); + Namespace ns1 = getNs(moduleName, ctx); + if (ns1 != null) { + ns = ns1; + } + } + + SchemaNode child = getChildSchemaNode(curSchema, childName, ns); + + if (child == null && childName.contains(UNDERSCORE)) { + String[] children = childName.split(UNDERSCORE); + String second = childName.substring(children[0].length() + 1); + StringBuilder first = new StringBuilder(); + + for (int i =0; i< children.length; i++) { + String moduleName = first + children[i]; + Namespace newNs = getNs(moduleName, ctx); + if (newNs != null) { + return newNs; + } + first.append(children[i]).append(UNDERSCORE); + if (i + 1 < children.length) { + second = second.replaceFirst( + children[i + 1] + UNDERSCORE, ""); + } + } + return ns; + } + return ns; + } + + /** + * Returns the namespace by finding the given module in the schema context. + * + * @param modName module name + * @param ctx schema context + * @return namespace of the given node name + */ + private static Namespace getNs(String modName, SchemaContext ctx) { + Iterator<Module> it = ctx.findModules(modName).iterator(); + if (it.hasNext()) { + Module m = it.next(); + return new Namespace(modName, m.getQNameModule().getNamespace(), + getRevision(m.getRevision())); + } + return null; + } + + /** + * Returns child schema node. + * + * @param curSchema current schema node + * @param name name of the property + * @param namespace namespace of the property + * @return child schema node + */ + public static SchemaNode getChildSchemaNode(SchemaNode curSchema, + String name, + Namespace namespace) { + if (namespace == null) { + return null; + } + + QName qname = QName.create(namespace.moduleNs(), + Revision.of(namespace.revision()), name); + + // YANG RPC will not be instance of DataSchemaNode + if (curSchema instanceof DataSchemaNode) { + Deque<DataSchemaNode> schemaNodeDeque = ParserStreamUtils. + findSchemaNodeByNameAndNamespace(((DataSchemaNode) + curSchema), name, namespace.moduleNs()); + if (schemaNodeDeque.isEmpty()) { + // could not find schema node + return null; + } + + DataSchemaNode schemaNode = schemaNodeDeque.pop(); + if (schemaNodeDeque.isEmpty()){ + // Simple node + return schemaNode; + } + + // node is child of Choice/case + return SchemaUtils.findSchemaForChild(((ChoiceSchemaNode) schemaNode), + qname); + } else { + return SchemaUtils.findDataChildSchemaByQName(curSchema, qname); + } + } + + /** + * Returns the property node type. + * + * @param index current index + * @param length length of the properties + * @param name name of the property + * @return the property node type + */ + public static NodeType getNodeType(int index, int length, String name, + SchemaNode schema) { + if (index == length-1) { + if (schema instanceof AnyXmlSchemaNode){ + return NodeType.ANY_XML_NODE; + } + return (isListEntry(name) ? NodeType.MULTI_INSTANCE_LEAF_NODE : + NodeType.SINGLE_INSTANCE_LEAF_NODE); + } else { + return (isListEntry(name) ? NodeType.MULTI_INSTANCE_NODE : + NodeType.SINGLE_INSTANCE_NODE); + } + } + + /** + * Returns revision in string. + * + * @param r YANG revision + * @return revision in string + */ + public static String getRevision(Optional<Revision> r) { + return (r.isPresent()) ? r.get().toString() : null; + } + + /** + * Returns value namespace for leaf value. + * + * @param value value of the leaf + * @param ctx schema context + * @return value namespace + * @throws SvcLogicException if identity/module could not be found + */ + static Namespace getValueNamespace(String value, + SchemaContext ctx) + throws SvcLogicException { + String prefix = getPrefixFromValue(value); + if (prefix == null) { + return null; + } + + IdentitySchemaNode id = IdentityCodecUtil.parseIdentity(value, + ctx, + prefixToModule -> { + final Iterator<Module> modules = ctx.findModules(prefix).iterator(); + checkArgument(modules.hasNext(), "Could not find " + + "module %s", prefix); + return modules.next().getQNameModule(); + }); + + if (id == null) { + throw new SvcLogicException("Could not find identity"); + } + + return getModuleNamespace(id.getQName(), ctx); + } + + private static String getPrefixFromValue(String value) { + int lastIndexOfColon = value.lastIndexOf(":"); + if (lastIndexOfColon != -1) { + return value.substring(0, lastIndexOfColon); + } + return null; + } + + /** + * Returns module namespace from a given qName. + * + * @param qName qName of a node + * @param ctx schema context + * @return module namespace of the node + * @throws SvcLogicException when the module is not available + */ + public static Namespace getModuleNamespace(QName qName, SchemaContext ctx) + throws SvcLogicException { + Optional<Module> module = ctx.findModule(qName.getModule()); + if (!module.isPresent()) { + throw new SvcLogicException("Could not find module node"); + } + Module m = module.get(); + return new Namespace(m.getName(), m.getQNameModule().getNamespace(), + getRevision(m.getRevision())); + } + + static String getParsedValue(Namespace valNs, String value) { + if (valNs != null && value.contains(":")) { + String[] valArr = value.split(":"); + return valArr[1]; + } + return value; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MultiInstanceNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MultiInstanceNode.java new file mode 100644 index 000000000..c251cdaea --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MultiInstanceNode.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Representation of multi instance node in properties data tree. + */ +public class MultiInstanceNode extends InnerNode<DataNodeChild> implements ListHolderChild { + + public MultiInstanceNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appinfo, NodeType nodeType) { + super(name, namespace, uri, parent, appinfo, nodeType); + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/Namespace.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/Namespace.java new file mode 100644 index 000000000..4f27ee1e7 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/Namespace.java @@ -0,0 +1,100 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.net.URI; + +/** + * Representation of YANG namespace. + */ +public class Namespace { + private String moduleName; + private URI moduleNs; + private String revision; + + /** + * Creates an instance of namespace with specified module name, + * namespace and revision. + * + * @param modulename module name + * @param moduleNs module namespace + * @param revision revision + */ + public Namespace(String modulename, URI moduleNs, String revision) { + this.moduleName = modulename; + this.moduleNs = moduleNs; + this.revision = revision; + } + + /** + * Returns module name. + * + * @return module name + */ + public String moduleName() { + return moduleName; + } + + /** + * Sets module name. + * + * @param moduleName module name + */ + public void moduleName(String moduleName) { + this.moduleName = moduleName; + } + + /** + * Sets module namespace. + * + * @return module namespace + */ + public URI moduleNs() { + return moduleNs; + } + + /** + * Sets module namespace. + * + * @param moduleNs module namespace + */ + public void moduleNs(URI moduleNs) { + this.moduleNs = moduleNs; + } + + /** + * Returns revision. + * + * @return revision + */ + public String revision() { + return revision; + } + + /** + * Sets revision. + * + * @param revision revision + */ + public void revision(String revision) { + this.revision = revision; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeChild.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeChild.java new file mode 100644 index 000000000..d482c6763 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeChild.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of an entity that represents child's of a node. + */ +public interface NodeChild { + +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeType.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeType.java new file mode 100644 index 000000000..0b6974e3e --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeType.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Representation of types of node in properties node tree. + */ +public enum NodeType { + SINGLE_INSTANCE_NODE, + MULTI_INSTANCE_NODE, + SINGLE_INSTANCE_LEAF_NODE, + MULTI_INSTANCE_LEAF_NODE, + MULTI_INSTANCE_HOLDER_NODE, + MULTI_INSTANCE_LEAF_HOLDER_NODE, + ANY_XML_NODE +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNode.java new file mode 100644 index 000000000..7e0ad631e --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNode.java @@ -0,0 +1,280 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of properties node data tree. This intermediate representation + * will enable data format serializers to be agnostic of DG context memory + * nuances and thereby will enable faster development of new data format + * serializers. + */ +public abstract class PropertiesNode { + + private String name; + private Namespace namespace; + private String uri; + private PropertiesNode parent; + private Object appInfo; + private NodeType nodeType; + private boolean nonAppend; + private Multimap<Object, PropertiesNode> augmentations = ArrayListMultimap.create(); + + /** + * Creates an instance of properties node. + * + * @param name name of node + * @param namespace namespace of node, null indicates parent namespace + * @param uri URI of this node, if null its calculated based on parent and + * current value of name and namespace + * @param parent parent's node + * @param appInfo application related information + * @param nodeType node type + */ + protected PropertiesNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, NodeType nodeType) { + this.name = name; + this.namespace = namespace; + this.uri = uri; + this.parent = parent; + this.appInfo = appInfo; + this.nodeType = nodeType; + } + + /** + * Sets name. + * + * @param name name of the node + */ + public void name(String name) { + this.name = name; + } + + /** + * Sets namespace. + * + * @param namespace namespace of the node + */ + public void namespace(Namespace namespace) { + this.namespace = namespace; + } + + /** + * Sets uri. + * + * @param uri uri of the node + */ + public void uri(String uri) { + this.uri = uri; + } + + /** + * Sets parent node. + * + * @param parent parent node + */ + public void parent(PropertiesNode parent) { + this.parent = parent; + } + + /** + * Sets application info. + * + * @param appInfo application info + */ + public void appInfo(Object appInfo) { + this.appInfo = appInfo; + } + + /** + * Sets to true if module name is required in forming a request; false + * otherwise. + * + * @param isNotReq true if required; false otherwise + */ + public void nonAppend(boolean isNotReq) { + this.nonAppend = isNotReq; + } + + /** + * Returns parent. + * + * @return parent node + */ + public PropertiesNode parent() { + return parent; + } + + /** + * Returns name. + * + * @return name of the node + */ + public String name() { + return name; + } + + /** + * Returns namespace. + * + * @return namespace of the node + */ + public Namespace namespace() { + return namespace; + } + + /** + * Returns uri. + * + * @return uri of the node + */ + public String uri() { + return uri; + } + + /** + * Returns application info. + * + * @return application info + */ + public Object appInfo() { + return appInfo; + } + + /** + * Returns node type. + * + * @return node type + */ + public NodeType nodeType() { + return nodeType; + } + + /** + * Returns if module name is required. + * + * @return status of module name if required + */ + public boolean nonAppend() { + return nonAppend; + } + + /** + * Returns augmentations. + * + * @return augmentations + */ + public Multimap<Object, PropertiesNode> augmentations() { + return augmentations; + } + + /** + * Sets augmentations. + * + * @param augmentations augmentations of the node + */ + public void augmentations(Multimap<Object, PropertiesNode> augmentations) { + this.augmentations = augmentations; + } + + /** + * Adds a child to a current node. + * + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param appInfo application info + * @return added properties node + */ + public abstract PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException; + + /** + * Adds a child with value to a current node. + * + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param value value of node + * @param valueNs value namespace + * @param appInfo application info + * @throws SvcLogicException if failed to add child + * @return added properties node + */ + public abstract PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException; + + /** + * Adds a child at a given index to a current node. To be used in case of + * leaf holder child's which is multi instance node. + * + * @param index index at which node is to be added + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param appInfo application info + * @throws SvcLogicException if failed to add child + * @return added properties node + */ + public abstract PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException; + + /** + * Adds a child at a given index to a current node. To be used in case of + * leaf holder child's which is multi instance node. + * + * @param index index at which node is to be added + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param value value of node + * @param valueNs value namespace + * @param appInfo application info + * @throws SvcLogicException if failed to add child + * @return added properties node + */ + public abstract PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException; + + /** + * Returns root node. + * + * @return root node + */ + public PropertiesNode endNode() { + PropertiesNode node = this; + while (node.parent() != null){ + node = node.parent(); + } + return node; + } +} + diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java new file mode 100644 index 000000000..7b97ffaf8 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of properties node listener. + */ +public interface PropertiesNodeListener { + + /** + * Pre-configurations required before starting the walking. + * + * @param node properties node + * @throws SvcLogicException when the pre-configuration fails + */ + void start(PropertiesNode node) throws SvcLogicException; + + /** + * Post-configurations required after starting the walking. + * + * @param node properties node + * @throws SvcLogicException when the post-configuration fails + */ + void end(PropertiesNode node) throws SvcLogicException; + + /** + * Enters the properties node. + * + * @param node properties node + * @throws SvcLogicException when entering the properties node fails + */ + void enterPropertiesNode(PropertiesNode node) throws SvcLogicException; + + /** + * Enters the properties node. + * + * @param node properties node + * @throws SvcLogicException when exiting the properties node fails + */ + void exitPropertiesNode(PropertiesNode node) throws SvcLogicException; +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java new file mode 100644 index 000000000..fe6fed484 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.Map; + +/** + * Abstraction of an entity to enable encoding and decoding of properties + * to an abstract properties node tree using YANG based schema. + * This serializer will be used by other data format serializers and will keep + * them abstract from properties nuances thereby enabling quick addition of any + * new data format serializer. + * + * @param <T> type of schema node + * @param <P> schema context of the model + */ +public abstract class PropertiesNodeSerializer<T, P> { + + /** + * Schema node from which the property is made. + */ + private T schemaNode; + + /** + * Schema context of the model. + */ + private P schemaCtx; + + /** + * URL pointing to the schema node. + */ + private String uri; + + /** + * Creates the properties node serializer. + * + * @param schemaNode schema node. + * @param schemaCtx schema context + * @param uri URL of the request + */ + public PropertiesNodeSerializer(T schemaNode, P schemaCtx, String uri) { + this.schemaNode = schemaNode; + this.schemaCtx = schemaCtx; + this.uri = uri; + } + + /** + * Encodes from properties to properties-node tree. + * + * @param paramMap parameter map + * @throws SvcLogicException fails to encode properties to properties node + * @return properties node + */ + public abstract PropertiesNode encode(Map<String, String> paramMap) throws SvcLogicException; + + /** + * Decodes from properties-node to properties map. + * + * @param propertiesNode properties-node + * @return parameter map + * @throws SvcLogicException fails to decode properties node to properties + */ + public abstract Map<String, String> decode(PropertiesNode propertiesNode) + throws SvcLogicException; + + /** + * Returns the schema node of the property + * + * @return schema node + */ + public T schemaNode(){ + return schemaNode; + } + + /** + * Returns the schema context + * + * @return schema node + */ + public P schemaCtx() { + return schemaCtx; + } + + /** + * Returns the URI. + * + * @return uri + */ + public String uri() { + return uri; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java new file mode 100644 index 000000000..36ee4dd9d --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of properties node walker + */ +public interface PropertiesNodeWalker { + /** + * Walks the properties node with the listener. + * + * @param listener properties node listener. + * @param propertiesNode properties node + * @throws SvcLogicException when walking the properties node fails + */ + void walk(PropertiesNodeListener listener, PropertiesNode propertiesNode) + throws SvcLogicException; +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java new file mode 100644 index 000000000..c7f7340fd --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java @@ -0,0 +1,212 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; + +import java.util.HashMap; +import java.util.Map; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.addToAugmentations; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.createNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getAugmentationNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getUri; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.isNamespaceAsParent; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.resolveName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findCorrespondingAugment; + +/** + * Abstraction of node representing properties data tree. + */ +public class RootNode<T extends NodeChild> extends PropertiesNode { + + private Map<String, T> children = new HashMap<String, T>(); + + /** + * Creates an instance of the root node to build the properties. + * + * @param name name of the node + * @param namespace namespace of the node + * @param appInfo application info + * @param uri URI of the node + */ + public RootNode(String name, Namespace namespace, + Object appInfo, String uri) { + super(name, namespace, uri, null, appInfo, null); + } + + /** + * Returns children. + * + * @return children + */ + public Map<String, T> children() { + return children; + } + + /** + * Sets children. + * + * @param children child nodes + */ + public void children(Map<String, T> children) { + this.children = children; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + PropertiesNode node = ((PropertiesNode) children.get(name)); + if (node != null) { + return node; + } + + // get augment schema, if it is augmented node + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, name); + } + + // create node based on type, this api will be invoked only for these three types + if (node == null) { + String uri = getUri(this, name, namespace); + node = createNode(name, namespace, uri, this, appInfo, type); + } + + // If namespace is not same as parent then it is augmented node + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valuens, + Object appInfo) throws SvcLogicException { + LeafNode node = ((LeafNode) children.get(name)); + if (node != null) { + return node; + } + + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + } + + String uri = getUri(this, name, namespace); + node = new LeafNode(name, namespace, uri, this, + appInfo, type, value); + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + Object appInfo) throws SvcLogicException { + String localname = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localname)); + if (node == null) { + String uri = getUri(this, name, namespace); + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localname); + } + + if (node == null) { + node = new ListHolderNode(localname, namespace, uri, + this, appInfo, MULTI_INSTANCE_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localname, ((T) node)); + } + node = node.addChild(index, localname, namespace, type, appInfo); + } else if (node instanceof ListHolderNode) { + ListHolderChild child = ((ListHolderNode) node).child(index); + node = (child != null ? ((MultiInstanceNode) child) : + node.addChild(index, localname, namespace, type, appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + String localName = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localName)); + if (node == null) { + String uri = getUri(this, name, namespace); + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localName); + } + + if (node == null) { + node = new LeafListHolderNode(localName, namespace, uri, this, + appInfo, MULTI_INSTANCE_LEAF_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localName, ((T) node)); + } + node = node.addChild(index, localName, namespace, type, value, valueNs, appInfo); + } else if (node instanceof LeafListHolderNode) { + LeafNode child = ((LeafNode) ((HolderNode) node).child(index)); + node = (child != null ? child : node.addChild(index, localName, + namespace, type, + value, valueNs, + appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SchemaPathHolder.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SchemaPathHolder.java new file mode 100644 index 000000000..4ef1bc664 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SchemaPathHolder.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; + +/** + * Representation of a holder for a proper path and its corresponding schema. + */ +public class SchemaPathHolder { + + /** + * Schema context for the path. + */ + private InstanceIdentifierContext insId; + + /** + * Formatted path. + */ + private String uri; + + /** + * Constructs schema path holder with path and its schema. + * + * @param insId instance identifier context + * @param uri path + */ + public SchemaPathHolder(InstanceIdentifierContext insId, String uri) { + this.insId = insId; + this.uri = uri; + } + + /** + * Returns the instance identifier context of the path. + * + * @return schema of the path + */ + public InstanceIdentifierContext getInsId() { + return insId; + } + + /** + * Returns the formatted path. + * + * @return formatted path + */ + public String getUri() { + return uri; + } + + /** + * Sets the formatted path. + * + * @param uri formatted path + */ + public void setUri(String uri) { + this.uri = uri; + } +} diff --git a/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SingleInstanceNode.java b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SingleInstanceNode.java new file mode 100644 index 000000000..6eb24c1a4 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SingleInstanceNode.java @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Representation of single instance node in properties data tree. + */ +public class SingleInstanceNode extends InnerNode<DataNodeChild> implements DataNodeChild { + + public SingleInstanceNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, + NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } +} diff --git a/plugins/restconf-client/provider/src/main/resources/OSGI-INF/blueprint/restconf-client-blueprint.xml b/plugins/restconf-client/provider/src/main/resources/OSGI-INF/blueprint/restconf-client-blueprint.xml new file mode 100755 index 000000000..45c335b13 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/resources/OSGI-INF/blueprint/restconf-client-blueprint.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + --> + +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" + odl:use-default-for-reference-types="true"> + + <reference xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0" + id="restapiCallNodeProvider" + interface="org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode" + ext:proxy-method="classes"/> + + <bean id="restconfapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode" > + <argument ref="restapiCallNodeProvider"/> + </bean> + + <bean id="restconfDiscoveryNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode" > + <argument ref="restconfapiCallNodeProvider"/> + </bean> + + <service ref="restconfapiCallNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode</value> + </interfaces> + </service> + + <service ref="restconfDiscoveryNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode</value> + </interfaces> + </service> + +</blueprint>
\ No newline at end of file diff --git a/plugins/restconf-client/provider/src/main/resources/org/opendaylight/blueprint/restconf-client-blueprint.xml b/plugins/restconf-client/provider/src/main/resources/org/opendaylight/blueprint/restconf-client-blueprint.xml new file mode 100755 index 000000000..45c335b13 --- /dev/null +++ b/plugins/restconf-client/provider/src/main/resources/org/opendaylight/blueprint/restconf-client-blueprint.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + --> + +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" + odl:use-default-for-reference-types="true"> + + <reference xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0" + id="restapiCallNodeProvider" + interface="org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode" + ext:proxy-method="classes"/> + + <bean id="restconfapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode" > + <argument ref="restapiCallNodeProvider"/> + </bean> + + <bean id="restconfDiscoveryNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode" > + <argument ref="restconfapiCallNodeProvider"/> + </bean> + + <service ref="restconfapiCallNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode</value> + </interfaces> + </service> + + <service ref="restconfDiscoveryNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode</value> + </interfaces> + </service> + +</blueprint>
\ No newline at end of file |