2 * Copyright (c) 2014 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.yangtools.yang.data.util;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import java.util.Map.Entry;
15 import javax.xml.XMLConstants;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.common.QNameModule;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
24 import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
25 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.util.LeafrefResolver;
29 * Abstract utility class for representations which encode {@link YangInstanceIdentifier} as a
30 * prefix:name tuple. Typical uses are RESTCONF/JSON (module:name) and XML (prefix:name).
33 public abstract class AbstractStringInstanceIdentifierCodec extends AbstractNamespaceCodec<YangInstanceIdentifier>
34 implements InstanceIdentifierCodec<String> {
36 protected final String serializeImpl(final YangInstanceIdentifier data) {
37 final StringBuilder sb = new StringBuilder();
38 DataSchemaContextNode<?> current = getDataContextTree().getRoot();
39 QNameModule lastModule = null;
40 for (PathArgument arg : data.getPathArguments()) {
41 current = current.getChild(arg);
42 checkArgument(current != null, "Invalid input %s: schema for argument %s (after %s) not found", data, arg,
45 if (current.isMixin()) {
47 * XML/YANG instance identifier does not have concept
48 * of augmentation identifier, or list as whole which
49 * identifies a mixin (same as the parent element),
50 * so we can safely ignore it if it is part of path
51 * (since child node) is identified in same fashion.
56 final QName qname = arg.getNodeType();
58 appendQName(sb, qname, lastModule);
59 lastModule = qname.getModule();
61 if (arg instanceof NodeIdentifierWithPredicates) {
62 for (Entry<QName, Object> entry : ((NodeIdentifierWithPredicates) arg).entrySet()) {
63 appendQName(sb.append('['), entry.getKey(), lastModule);
64 sb.append("='").append(String.valueOf(entry.getValue())).append("']");
66 } else if (arg instanceof NodeWithValue) {
67 sb.append("[.='").append(((NodeWithValue<?>) arg).getValue()).append("']");
74 * Returns DataSchemaContextTree associated with SchemaContext for which
75 * serialization / deserialization occurs.
78 * Implementations MUST provide non-null Data Tree context, in order
79 * for correct serialization / deserialization of PathArguments,
80 * since XML representation does not have Augmentation arguments
81 * and does not provide path arguments for cases.
84 * This effectively means same input XPath representation of Path Argument
85 * may result in different YangInstanceIdentifiers if models are different
86 * in uses of choices and cases.
88 * @return DataSchemaContextTree associated with SchemaContext for which
89 * serialization / deserialization occurs.
91 protected abstract @NonNull DataSchemaContextTree getDataContextTree();
93 protected Object deserializeKeyValue(final DataSchemaNode schemaNode, final LeafrefResolver resolver,
99 protected final YangInstanceIdentifier deserializeImpl(final String data) {
100 XpathStringParsingPathArgumentBuilder builder = new XpathStringParsingPathArgumentBuilder(this,
101 requireNonNull(data));
102 return YangInstanceIdentifier.create(builder.build());
106 * Create QName from unprefixed name, potentially taking last QNameModule encountered into account.
108 * @param lastModule last QNameModule encountered, potentially null
109 * @param localName Local name string
110 * @return A newly-created QName
112 protected QName createQName(final @Nullable QNameModule lastModule, final String localName) {
113 // This implementation handles both XML encoding, where we follow XML namespace rules and old JSON encoding,
114 // which is the same thing: always encode prefixes
115 return createQName(XMLConstants.DEFAULT_NS_PREFIX, localName);