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