2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.restconf.parser.builder;
10 import com.google.common.base.Preconditions;
12 import java.util.Iterator;
13 import java.util.Map.Entry;
14 import org.opendaylight.restconf.utils.RestconfConstants;
15 import org.opendaylight.restconf.utils.parser.builder.ParserBuilderConstants;
16 import org.opendaylight.restconf.utils.parser.builder.ParserBuilderConstants.Serializer;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.common.QNameModule;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
23 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
24 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
25 import org.opendaylight.yangtools.yang.model.api.Module;
26 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 * Serializer for {@link YangInstanceIdentifier} to {@link String} for restconf.
31 * @deprecated move to splitted module restconf-nb-rfc8040
34 public final class YangInstanceIdentifierSerializer {
36 private YangInstanceIdentifierSerializer() {
37 throw new UnsupportedOperationException("Util class.");
41 * Method to create String from {@link Iterable} of {@link PathArgument}
42 * which are parsing from data by {@link SchemaContext}.
44 * @param schemaContext
45 * for validate of parsing path arguments
48 * @return {@link String}
50 public static String create(final SchemaContext schemaContext, final YangInstanceIdentifier data) {
51 final DataSchemaContextNode<?> current = DataSchemaContextTree.from(schemaContext).getRoot();
52 final MainVarsWrapper variables = new MainVarsWrapper(current);
53 final StringBuilder path = new StringBuilder();
55 QNameModule parentModule = null;
56 for (int i = 0; i < data.getPathArguments().size(); i++) {
57 // get module of the parent
58 if (!variables.getCurrent().isMixin()) {
59 parentModule = variables.getCurrent().getDataSchemaNode().getQName().getModule();
62 final PathArgument arg = data.getPathArguments().get(i);
63 variables.setCurrent(variables.getCurrent().getChild(arg));
65 Preconditions.checkArgument(variables.getCurrent() != null,
66 "Invalid input %s: schema for argument %s (after %s) not found", data, arg, path);
68 if (variables.getCurrent().isMixin()) {
72 // append namespace before every node which is defined in other module than its parent
73 // condition is satisfied also for the first path argument
74 if (!arg.getNodeType().getModule().equals(parentModule)) {
75 // append slash if it is not the first path argument
76 if (path.length() > 0) {
77 path.append(RestconfConstants.SLASH);
80 path.append(prefixForNamespace(arg.getNodeType(), schemaContext));
81 path.append(ParserBuilderConstants.Deserializer.COLON);
83 path.append(RestconfConstants.SLASH);
86 if (arg instanceof NodeIdentifierWithPredicates) {
87 prepareNodeWithPredicates(path, arg);
88 } else if (arg instanceof NodeWithValue) {
89 prepareNodeWithValue(path, arg);
91 appendQName(path, arg.getNodeType());
95 return path.toString();
98 private static void prepareNodeWithValue(final StringBuilder path, final PathArgument arg) {
99 path.append(arg.getNodeType().getLocalName());
100 path.append(ParserBuilderConstants.Deserializer.EQUAL);
102 String value = String.valueOf(((NodeWithValue<String>) arg).getValue());
103 if (Serializer.PERCENT_ENCODE_CHARS.matchesAnyOf(value)) {
104 value = parsePercentEncodeChars(value);
109 private static void prepareNodeWithPredicates(final StringBuilder path, final PathArgument arg) {
110 path.append(arg.getNodeType().getLocalName());
112 final Iterator<Entry<QName, Object>> iterator = ((NodeIdentifierWithPredicates) arg).getKeyValues()
113 .entrySet().iterator();
115 if (iterator.hasNext()) {
116 path.append(ParserBuilderConstants.Deserializer.EQUAL);
119 while (iterator.hasNext()) {
120 String valueOf = String.valueOf(iterator.next().getValue());
121 if (Serializer.PERCENT_ENCODE_CHARS.matchesAnyOf(valueOf)) {
122 valueOf = parsePercentEncodeChars(valueOf);
124 path.append(valueOf);
125 if (iterator.hasNext()) {
126 path.append(ParserBuilderConstants.Deserializer.COMMA);
132 * Encode {@link Serializer#DISABLED_CHARS} chars to percent encoded chars.
136 * @return encoded {@link String}
138 private static String parsePercentEncodeChars(final String valueOf) {
139 final StringBuilder sb = new StringBuilder();
141 while (start < valueOf.length()) {
142 if (Serializer.PERCENT_ENCODE_CHARS.matches(valueOf.charAt(start))) {
143 final String format = String.format("%x", (int) valueOf.charAt(start));
144 final String upperCase = format.toUpperCase();
145 sb.append(ParserBuilderConstants.Deserializer.PERCENT_ENCODING + upperCase);
147 sb.append(valueOf.charAt(start));
151 return sb.toString();
155 * Add {@link QName} to the serialized string.
158 * {@link StringBuilder}
161 * @return {@link StringBuilder}
163 private static StringBuilder appendQName(final StringBuilder path, final QName qname) {
164 path.append(qname.getLocalName());
169 * Create prefix of namespace from {@link QName}.
173 * @return {@link String}
175 private static String prefixForNamespace(final QName qname, final SchemaContext schemaContext) {
176 final URI namespace = qname.getNamespace();
177 Preconditions.checkArgument(namespace != null, "Failed to map QName {}", qname);
178 final Module module = schemaContext.findModuleByNamespaceAndRevision(namespace, qname.getRevision());
179 return module.getName();
182 private static final class MainVarsWrapper {
184 private DataSchemaContextNode<?> current;
186 MainVarsWrapper(final DataSchemaContextNode<?> current) {
187 this.setCurrent(current);
190 public DataSchemaContextNode<?> getCurrent() {
194 public void setCurrent(final DataSchemaContextNode<?> current) {
195 this.current = current;