f52b21495ac18c6ffe0bbf91452da8387b0ba739
[yangtools.git] / yang / yang-common / src / main / java / org / opendaylight / yangtools / yang / common / QName.java
1 /*
2  * Copyright (c) 2013 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.common;
9
10 import java.io.Serializable;
11 import java.net.URI;
12 import java.net.URISyntaxException;
13 import java.text.ParseException;
14 import java.text.SimpleDateFormat;
15 import java.util.Date;
16
17 import org.opendaylight.yangtools.concepts.Immutable;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20 import org.opendaylight.yangtools.yang.common.QName;
21
22 /**
23  * The QName from XML consists of local name of element and XML namespace, but
24  * for our use, we added module revision to it.
25  *
26  * In YANG context QName is full name of defined node, type, procedure or
27  * notification. QName consists of XML namespace, YANG model revision and local
28  * name of defined type. It is used to prevent name clashes between nodes with
29  * same local name, but from different schemas.
30  *
31  * <ul>
32  * <li><b>XMLNamespace</b> - the namespace assigned to the YANG module which
33  * defined element, type, procedure or notification.</li>
34  * <li><b>Revision</b> - the revision of the YANG module which describes the
35  * element</li>
36  * <li><b>LocalName</b> - the YANG schema identifier which were defined for this
37  * node in the YANG module</li>
38  * </ul>
39  *
40  *
41  */
42 public final class QName implements Immutable,Serializable {
43
44     private static final long serialVersionUID = 5398411242927766414L;
45
46     protected static final Logger LOGGER = LoggerFactory.getLogger(QName.class);
47
48     private static final ThreadLocal<SimpleDateFormat> REVISION_FORMAT = new ThreadLocal<SimpleDateFormat>() {
49
50         protected SimpleDateFormat initialValue() {
51             return new SimpleDateFormat("yyyy-MM-dd");
52         };
53
54         public void set(SimpleDateFormat value) {
55             throw new UnsupportedOperationException();
56         };
57
58     };
59
60     private final URI namespace;
61     private final String localName;
62     private final String prefix;
63     private final String formattedRevision;
64     private final Date revision;
65
66     /**
67      * QName Constructor.
68      *
69      * @param namespace
70      *            the namespace assigned to the YANG module
71      * @param revision
72      *            the revision of the YANG module
73      * @param prefix
74      *            locally defined prefix assigned to local name
75      * @param localName
76      *            YANG schema identifier
77      */
78     public QName(URI namespace, Date revision, String prefix, String localName) {
79         this.namespace = namespace;
80         this.localName = localName;
81         this.revision = revision;
82         this.prefix = prefix;
83         if(revision != null) {
84             this.formattedRevision = REVISION_FORMAT.get().format(revision);
85         } else {
86             this.formattedRevision = null;
87         }
88     }
89
90     /**
91      * QName Constructor.
92      *
93      * @param namespace
94      *            the namespace assigned to the YANG module
95      * @param localName
96      *            YANG schema identifier
97      */
98     public QName(URI namespace, String localName) {
99         this(namespace, null, "", localName);
100     }
101
102     /**
103      * QName Constructor.
104      *
105      * @param namespace
106      *            the namespace assigned to the YANG module
107      * @param revision
108      *            the revision of the YANG module
109      * @param localName
110      *            YANG schema identifier
111      */
112     public QName(URI namespace, Date revision, String localName) {
113         this(namespace, revision, null, localName);
114     }
115
116     public QName(QName base, String localName) {
117         this(base.getNamespace(), base.getRevision(), base.getPrefix(), localName);
118     }
119
120     // TODO: rework with pattern
121     public QName(String base) throws ParseException {
122         Date revision = null;
123         String nsAndRev = base.substring(base.indexOf("(") + 1, base.indexOf(")"));
124         if (nsAndRev.contains("?")) {
125             String[] splitted = nsAndRev.split("\\?");
126             this.namespace = URI.create(splitted[0]);
127             revision = REVISION_FORMAT.get().parse(splitted[1]);
128         } else {
129             this.namespace = URI.create(nsAndRev);
130         }
131
132         this.localName = base.substring(base.indexOf(")") + 1);
133         this.revision = revision;
134         this.prefix = null;
135         if (revision != null) {
136             this.formattedRevision = REVISION_FORMAT.get().format(revision);
137         } else {
138             this.formattedRevision = null;
139         }
140     }
141
142     /**
143      * Returns XMLNamespace assigned to the YANG module.
144      *
145      * @return XMLNamespace assigned to the YANG module.
146      */
147     public URI getNamespace() {
148         return namespace;
149     }
150
151     /**
152      * Returns YANG schema identifier which were defined for this node in the
153      * YANG module
154      *
155      * @return YANG schema identifier which were defined for this node in the
156      *         YANG module
157      */
158     public String getLocalName() {
159         return localName;
160     }
161
162     /**
163      * Returns revision of the YANG module if the module has defined revision,
164      * otherwise returns <code>null</code>
165      *
166      * @return revision of the YANG module if the module has defined revision,
167      *         otherwise returns <code>null</code>
168      */
169     public Date getRevision() {
170         return revision;
171     }
172
173     /**
174      * Returns locally defined prefix assigned to local name
175      *
176      * @return locally defined prefix assigned to local name
177      */
178     public String getPrefix() {
179         return prefix;
180     }
181
182     @Override
183     public int hashCode() {
184         final int prime = 31;
185         int result = 1;
186         result = prime * result + ((localName == null) ? 0 : localName.hashCode());
187         result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
188         result = prime * result + ((formattedRevision == null) ? 0 : formattedRevision.hashCode());
189         return result;
190     }
191
192     @Override
193     public boolean equals(Object obj) {
194         if (this == obj) {
195             return true;
196         }
197         if (obj == null) {
198             return false;
199         }
200         if (getClass() != obj.getClass()) {
201             return false;
202         }
203         QName other = (QName) obj;
204         if (localName == null) {
205             if (other.localName != null) {
206                 return false;
207             }
208         } else if (!localName.equals(other.localName)) {
209             return false;
210         }
211         if (namespace == null) {
212             if (other.namespace != null) {
213                 return false;
214             }
215         } else if (!namespace.equals(other.namespace)) {
216             return false;
217         }
218         if (formattedRevision == null) {
219             if (other.formattedRevision != null) {
220                 return false;
221             }
222         } else if (!revision.equals(other.revision)) {
223             return false;
224         }
225         return true;
226     }
227
228
229     public static QName create(QName base, String localName){
230         return new QName(base, localName);
231     }
232
233     public static QName create(URI namespace, Date revision, String localName){
234         return new QName(namespace, revision, localName);
235     }
236
237
238     public static QName create(String namespace, String revision, String localName) throws IllegalArgumentException{
239         try {
240             URI namespaceUri = new URI(namespace);
241             Date revisionDate = REVISION_FORMAT.get().parse(revision);
242             return create(namespaceUri, revisionDate, localName);
243         } catch (ParseException pe) {
244             throw new IllegalArgumentException("Revision is not in supported format", pe);
245         } catch (URISyntaxException ue) {
246             throw new IllegalArgumentException("Namespace is is not valid URI", ue);
247         }
248     }
249
250     @Override
251     public String toString() {
252         StringBuilder sb = new StringBuilder();
253         if (namespace != null) {
254             sb.append("(" + namespace);
255
256             if (revision != null) {
257                 sb.append("?revision=" + REVISION_FORMAT.get().format(revision));
258             }
259             sb.append(")");
260         }
261         sb.append(localName);
262         return sb.toString();
263     }
264
265     /**
266      * Returns a namespace in form defined by section 5.6.4. of {@link https
267      * ://tools.ietf.org/html/rfc6020}, if namespace is not correctly defined,
268      * the method will return <code>null</code> <br>
269      * example "http://example.acme.com/system?revision=2008-04-01"
270      *
271      * @return namespace in form defined by section 5.6.4. of {@link https
272      *         ://tools.ietf.org/html/rfc6020}, if namespace is not correctly
273      *         defined, the method will return <code>null</code>
274      *
275      */
276     URI getRevisionNamespace() {
277
278         if (namespace == null) {
279             return null;
280         }
281
282         String query = "";
283         if (revision != null) {
284             query = "revision=" + formattedRevision;
285         }
286
287         URI compositeURI = null;
288         try {
289             compositeURI = new URI(namespace.getScheme(), namespace.getUserInfo(), namespace.getHost(),
290                     namespace.getPort(), namespace.getPath(), query, namespace.getFragment());
291         } catch (URISyntaxException e) {
292             LOGGER.error("", e);
293         }
294         return compositeURI;
295     }
296
297     public String getFormattedRevision() {
298         return formattedRevision;
299     }
300
301     public QName withoutRevision() {
302         return QName.create(namespace, null, localName);
303     }
304 }