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;
13 import java.util.Map.Entry;
15 import org.opendaylight.restconf.utils.parser.builder.ParserBuilderConstants;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
21 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
22 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
23 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
26 * Serializer for {@link YangInstanceIdentifier} to {@link String} for restconf
29 public final class YangInstanceIdentifierSerializer {
31 private YangInstanceIdentifierSerializer() {
32 throw new UnsupportedOperationException("Util class.");
36 * Method to create String from {@link Iterable} of {@link PathArgument}
37 * which are parsing from data by {@link SchemaContext}
39 * @param schemaContext
40 * - for validate of parsing path arguments
43 * @return {@link String}
45 public static String create(final SchemaContext schemaContext, final YangInstanceIdentifier data) {
46 final DataSchemaContextNode<?> current = DataSchemaContextTree.from(schemaContext).getRoot();
47 final MainVarsWrappar variables = new YangInstanceIdentifierSerializer.MainVarsWrappar(current);
49 final StringBuilder path = prepareFirstArgForPath(variables, data);
51 for (int i = 1; i < data.getPathArguments().size(); i++) {
52 final PathArgument arg = data.getPathArguments().get(i);
53 variables.setCurrent(variables.getCurrent().getChild(arg));
54 Preconditions.checkArgument(current != null,
55 "Invalid input %s: schema for argument %s (after %s) not found", data, arg, path);
57 if (variables.getCurrent().isMixin()) {
62 if (arg instanceof NodeIdentifierWithPredicates) {
63 prepareNodeWithPredicates(path, arg);
64 } else if (arg instanceof NodeWithValue) {
65 prepareNodeWithValue(path, arg);
68 return path.toString();
71 private static void prepareNodeWithValue(final StringBuilder path, final PathArgument arg) {
72 path.append(arg.getNodeType().getLocalName());
75 String value = ((NodeWithValue<String>) arg).getValue();
76 if (ParserBuilderConstants.Serializer.PERCENT_ENCODE_CHARS.matchesAnyOf(value)) {
77 value = parsePercentEncodeChars(value);
82 private static void prepareNodeWithPredicates(final StringBuilder path, final PathArgument arg) {
83 path.append(arg.getNodeType().getLocalName());
86 final Set<Entry<QName, Object>> entrySet = ((NodeIdentifierWithPredicates) arg).getKeyValues().entrySet();
87 final int endOfSet = entrySet.size();
89 for (final Map.Entry<QName, Object> entry : entrySet) {
90 String valueOf = String.valueOf(entry.getValue());
91 if (ParserBuilderConstants.Serializer.PERCENT_ENCODE_CHARS.matchesAnyOf(valueOf)) {
92 valueOf = parsePercentEncodeChars(valueOf);
102 private static StringBuilder prepareFirstArgForPath(final MainVarsWrappar variables,
103 final YangInstanceIdentifier data) {
104 final PathArgument firstArg = data.getPathArguments().get(0);
105 variables.setCurrent(variables.getCurrent().getChild(firstArg));
107 final StringBuilder path = new StringBuilder("/");
108 appendQName(path, firstArg.getNodeType());
113 * Encode {@link YangInstanceIdentifierSerializer#DISABLED_CHARS}
114 * chars to percent encoded chars
118 * @return encoded {@link String}
120 private static String parsePercentEncodeChars(final String valueOf) {
121 final StringBuilder sb = new StringBuilder();
123 while (start < valueOf.length()) {
124 if (ParserBuilderConstants.Serializer.PERCENT_ENCODE_CHARS.matches(valueOf.charAt(start))) {
125 final String format = String.format("%x", (int) valueOf.charAt(start));
126 final String upperCase = format.toUpperCase();
127 sb.append("%" + upperCase);
129 sb.append(valueOf.charAt(start));
133 return sb.toString();
137 * Add {@link QName} to the serialized string
140 * - {@link StringBuilder}
142 * - {@link QName} node
143 * @return {@link StringBuilder}
145 private final static StringBuilder appendQName(final StringBuilder path, final QName qname) {
146 final String prefix = prefixForNamespace(qname.getNamespace());
147 Preconditions.checkArgument(prefix != null, "Failed to map QName {}", qname);
150 path.append(qname.getLocalName());
155 * Create prefix of namespace from {@link URI}
159 * @return {@link String}
161 private static String prefixForNamespace(final URI namespace) {
162 final String prefix = namespace.toString();
163 return prefix.replace(':', '-');
166 private static class MainVarsWrappar {
168 private DataSchemaContextNode<?> current;
170 public MainVarsWrappar(final DataSchemaContextNode<?> current) {
171 this.setCurrent(current);
174 public DataSchemaContextNode<?> getCurrent() {
178 public void setCurrent(final DataSchemaContextNode<?> current) {
179 this.current = current;