2 * Copyright (c) 2013 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.common;
10 import java.io.Serializable;
12 import java.net.URISyntaxException;
13 import java.text.ParseException;
14 import java.text.SimpleDateFormat;
15 import java.util.Date;
16 import java.util.Objects;
18 import org.opendaylight.yangtools.concepts.Immutable;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21 import org.opendaylight.yangtools.yang.common.QName;
24 * The QName from XML consists of local name of element and XML namespace, but
25 * for our use, we added module revision to it.
27 * In YANG context QName is full name of defined node, type, procedure or
28 * notification. QName consists of XML namespace, YANG model revision and local
29 * name of defined type. It is used to prevent name clashes between nodes with
30 * same local name, but from different schemas.
33 * <li><b>XMLNamespace</b> - the namespace assigned to the YANG module which
34 * defined element, type, procedure or notification.</li>
35 * <li><b>Revision</b> - the revision of the YANG module which describes the
37 * <li><b>LocalName</b> - the YANG schema identifier which were defined for this
38 * node in the YANG module</li>
43 public final class QName implements Immutable,Serializable {
45 private static final long serialVersionUID = 5398411242927766414L;
47 protected static final Logger LOGGER = LoggerFactory.getLogger(QName.class);
49 private static final ThreadLocal<SimpleDateFormat> REVISION_FORMAT = new ThreadLocal<SimpleDateFormat>() {
51 protected SimpleDateFormat initialValue() {
52 return new SimpleDateFormat("yyyy-MM-dd");
55 public void set(SimpleDateFormat value) {
56 throw new UnsupportedOperationException();
61 private final URI namespace;
62 private final String localName;
63 private final String prefix;
64 private final String formattedRevision;
65 private final Date revision;
71 * the namespace assigned to the YANG module
73 * the revision of the YANG module
75 * locally defined prefix assigned to local name
77 * YANG schema identifier
79 public QName(URI namespace, Date revision, String prefix, String localName) {
80 this.namespace = namespace;
81 this.localName = localName;
82 this.revision = revision;
84 if(revision != null) {
85 this.formattedRevision = REVISION_FORMAT.get().format(revision);
87 this.formattedRevision = null;
95 * the namespace assigned to the YANG module
97 * YANG schema identifier
99 public QName(URI namespace, String localName) {
100 this(namespace, null, "", localName);
107 * the namespace assigned to the YANG module
109 * the revision of the YANG module
111 * YANG schema identifier
113 public QName(URI namespace, Date revision, String localName) {
114 this(namespace, revision, null, localName);
117 public QName(QName base, String localName) {
118 this(base.getNamespace(), base.getRevision(), base.getPrefix(), localName);
121 // TODO: rework with pattern
122 public QName(String base) throws ParseException {
123 Date revision = null;
124 String nsAndRev = base.substring(base.indexOf("(") + 1, base.indexOf(")"));
125 if (nsAndRev.contains("?")) {
126 String[] splitted = nsAndRev.split("\\?");
127 this.namespace = URI.create(splitted[0]);
128 revision = REVISION_FORMAT.get().parse(splitted[1]);
130 this.namespace = URI.create(nsAndRev);
133 this.localName = base.substring(base.indexOf(")") + 1);
134 this.revision = revision;
136 if (revision != null) {
137 this.formattedRevision = REVISION_FORMAT.get().format(revision);
139 this.formattedRevision = null;
144 * Returns XMLNamespace assigned to the YANG module.
146 * @return XMLNamespace assigned to the YANG module.
148 public URI getNamespace() {
153 * Returns YANG schema identifier which were defined for this node in the
156 * @return YANG schema identifier which were defined for this node in the
159 public String getLocalName() {
164 * Returns revision of the YANG module if the module has defined revision,
165 * otherwise returns <code>null</code>
167 * @return revision of the YANG module if the module has defined revision,
168 * otherwise returns <code>null</code>
170 public Date getRevision() {
175 * Returns locally defined prefix assigned to local name
177 * @return locally defined prefix assigned to local name
179 public String getPrefix() {
184 public int hashCode() {
185 final int prime = 31;
187 result = prime * result + ((localName == null) ? 0 : localName.hashCode());
188 result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
189 result = prime * result + ((formattedRevision == null) ? 0 : formattedRevision.hashCode());
194 public boolean equals(Object obj) {
201 if (getClass() != obj.getClass()) {
204 QName other = (QName) obj;
205 if (localName == null) {
206 if (other.localName != null) {
209 } else if (!localName.equals(other.localName)) {
212 if (namespace == null) {
213 if (other.namespace != null) {
216 } else if (!namespace.equals(other.namespace)) {
219 if (formattedRevision == null) {
220 if (other.formattedRevision != null) {
223 } else if (!revision.equals(other.revision)) {
230 public static QName create(QName base, String localName){
231 return new QName(base, localName);
234 public static QName create(URI namespace, Date revision, String localName){
235 return new QName(namespace, revision, localName);
239 public static QName create(String namespace, String revision, String localName) throws IllegalArgumentException{
241 URI namespaceUri = new URI(namespace);
242 Date revisionDate = parseRevision(revision);
243 return create(namespaceUri, revisionDate, localName);
244 } catch (URISyntaxException ue) {
245 throw new IllegalArgumentException("Namespace is is not valid URI", ue);
250 public String toString() {
251 StringBuilder sb = new StringBuilder();
252 if (namespace != null) {
253 sb.append("(" + namespace);
255 if (revision != null) {
256 sb.append("?revision=" + REVISION_FORMAT.get().format(revision));
260 sb.append(localName);
261 return sb.toString();
265 * Returns a namespace in form defined by section 5.6.4. of {@link https
266 * ://tools.ietf.org/html/rfc6020}, if namespace is not correctly defined,
267 * the method will return <code>null</code> <br>
268 * example "http://example.acme.com/system?revision=2008-04-01"
270 * @return namespace in form defined by section 5.6.4. of {@link https
271 * ://tools.ietf.org/html/rfc6020}, if namespace is not correctly
272 * defined, the method will return <code>null</code>
275 URI getRevisionNamespace() {
277 if (namespace == null) {
282 if (revision != null) {
283 query = "revision=" + formattedRevision;
286 URI compositeURI = null;
288 compositeURI = new URI(namespace.getScheme(), namespace.getUserInfo(), namespace.getHost(),
289 namespace.getPort(), namespace.getPath(), query, namespace.getFragment());
290 } catch (URISyntaxException e) {
296 public String getFormattedRevision() {
297 return formattedRevision;
300 public QName withoutRevision() {
301 return QName.create(namespace, null, localName);
304 public static Date parseRevision(String formatedDate) {
306 return REVISION_FORMAT.get().parse(formatedDate);
307 } catch (ParseException e) {
308 throw new IllegalArgumentException("Revision is not in supported format",e);
312 public static String formattedRevision(Date revision) {
313 if(revision == null) {
316 return REVISION_FORMAT.get().format(revision);
319 public boolean isEqualWithoutRevision(QName other) {
320 return localName.equals(other.getLocalName()) && Objects.equals(namespace, other.getNamespace());