8e942ee499991c692e197575d9defb0a903df84c
[yangtools.git] / yang / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / AbstractNamespaceCodec.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.util;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import com.google.common.base.Splitter;
13 import java.net.URI;
14 import java.util.Iterator;
15 import javax.annotation.Nonnull;
16 import javax.annotation.Nullable;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.common.QNameModule;
19
20 abstract class AbstractNamespaceCodec {
21     private static final Splitter COLON_SPLITTER = Splitter.on(':');
22
23     /**
24      * Return string prefix for a particular namespace, allocating a new one if necessary.
25      *
26      * @param namespace Namespace to map
27      * @return Allocated unique prefix, or null if the prefix cannot be mapped.
28      */
29     @Nullable protected abstract String prefixForNamespace(@Nonnull URI namespace);
30
31     /**
32      * Create a QName for a prefix and local name.
33      *
34      * @param prefix Prefix for namespace
35      * @param localName local name
36      * @return QName
37      * @throws IllegalArgumentException if the prefix cannot be resolved
38      */
39     @Nullable protected abstract QName createQName(@Nonnull String prefix, @Nonnull String localName);
40
41     private static String getIdAndPrefixAsStr(final String pathPart) {
42         int predicateStartIndex = pathPart.indexOf('[');
43         return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
44     }
45
46     protected final StringBuilder appendQName(final StringBuilder sb, final QName qname) {
47         final String prefix = prefixForNamespace(qname.getNamespace());
48         checkArgument(prefix != null, "Failed to map QName %s to prefix", qname);
49         sb.append(prefix).append(':').append(qname.getLocalName());
50         return sb;
51     }
52
53     /**
54      * Append a QName, potentially taking into account last QNameModule encountered in the serialized path.
55      *
56      * @param sb target StringBuilder
57      * @param qname QName to append
58      * @param lastModule last QNameModule encountered, may be null
59      * @return target StringBuilder
60      */
61     protected StringBuilder appendQName(final StringBuilder sb, final QName qname,
62             final @Nullable QNameModule lastModule) {
63         // Covers XML and uncompressed JSON codec
64         return appendQName(sb, qname);
65     }
66
67     protected final QName parseQName(final String str) {
68         final String xPathPartTrimmed = getIdAndPrefixAsStr(str).trim();
69         final Iterator<String> it = COLON_SPLITTER.split(xPathPartTrimmed).iterator();
70
71         // Empty string
72         if (!it.hasNext()) {
73             return null;
74         }
75
76
77         final String first = it.next().trim();
78         if (first.isEmpty()) {
79             return null;
80         }
81
82         final String identifier;
83         final String prefix;
84         if (it.hasNext()) {
85             // It is "prefix:value"
86             prefix = first;
87             identifier = it.next().trim();
88         } else {
89             prefix = "";
90             identifier = first;
91         }
92         if (identifier.isEmpty()) {
93             return null;
94         }
95
96         return createQName(prefix, identifier);
97     }
98 }