1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package javax.xml.namespace;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.Serializable;
22
23 /**
24 * <code>QName</code> class represents the value of a qualified name
25 * as specified in <a href="http://www.w3.org/TR/xmlschema-2/#QName">XML
26 * Schema Part2: Datatypes specification</a>.
27 * <p>
28 * The WSDL4J version of QName has been copied and updated for Apache Woden to
29 * match the Javadoc of the QName class defined for Java 5.0 at:
30 * <br />
31 * http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/namespace/QName.html
32 * <p>
33 * The value of a QName contains a <b>namespaceURI</b>, a <b>localPart</b>
34 * and a <b>prefix</b>.
35 * The localPart provides the local part of the qualified name. The
36 * namespaceURI is a URI reference identifying the namespace. The prefix
37 * corresponds to a namespace declaration 'xmlns:somePrefix' in the underlying xml.
38 * <p>
39 * Note: Some of this impl code was taken from Axis.
40 * <p>
41 * The constructors throw an IllegalArgumentException if the 'localPart'
42 * argument is null, but if it is the empty string ("") they just create
43 * the QName object with the localPart set to the empty string.
44 * The 'prefix' property defaults to the empty string for the two
45 * constructors that do not take a 'prefix' argument.
46 * The constructor that does take a 'prefix' argument will throw an
47 * IllegalArgumentException if a null value is used (i.e. the absence
48 * of any 'prefix' must be specified explicitly as the empty string "").
49 * <p>
50 * The <code>valueOf</code> method behaves like the constructors in that
51 * a null value will throw an IllegalArgumentException, but an empty string ""
52 * value will be treated as a localPart rather than an IllegalArgumentException
53 * to retain compatibility with v1.0 QName.
54 * <p>
55 * To support the deserialization of objects that were serialized with an
56 * older version of QName (i.e. without a 'prefix' field), the
57 * <code>readObject</code> method will check if the 'prefix'
58 * value is null after default deserialization and if so, change it to the
59 * empty string.
60 *
61 * @author axis-dev
62 * @author <br/>Matthew J. Duftler (duftler@us.ibm.com)
63 * @author <br/>John Kaputin (jkaputin@apache.org)
64 */
65 public class QName implements Serializable
66 {
67 // Comment/shared empty string.
68 private static final String emptyString = "";
69
70 // Field namespaceURI.
71 private String namespaceURI;
72
73 // Field localPart.
74 private String localPart;
75
76 // Field prefix.
77 private String prefix;
78
79 private static final long serialVersionUID = -9120448754896609940L;
80
81 /**
82 * Constructor for the QName.
83 * Takes a localPart and sets the namespace and prefix to
84 * the empty string "".
85 *
86 * @param localPart Local part of the QName
87 *
88 * @throws IllegalArgumentException if localPart is null.
89 */
90 public QName(String localPart)
91 {
92 this(emptyString, localPart, emptyString);
93 }
94
95 /**
96 * Constructor for the QName.
97 * Takes a localPart and a namespace and sets the prefix to
98 * the empty string "". If namespace is null, it defaults to
99 * the empty string.
100 *
101 * @param namespaceURI Namespace URI for the QName
102 * @param localPart Local part of the QName.
103 *
104 * @throws IllegalArgumentException if localPart is null.
105 */
106 public QName(String namespaceURI, String localPart)
107 {
108 this(namespaceURI, localPart, emptyString);
109 }
110
111 /**
112 * Constructor for the QName.
113 * Takes a localPart, a namespace and a prefix. If the namespace is
114 * null, it defaults to the empty string "". The localPart and prefix
115 * cannot be null. If they are, an IllegalArgumentException is thrown.
116 * If there is no prefix, an empty string "" must be specified.
117 *
118 * @param namespaceURI Namespace URI for the QName
119 * @param localPart Local part of the QName.
120 * @param prefix the xmlns-declared prefix for this namespaceURI
121 *
122 * @throws IllegalArgumentException if localPart or prefix is null.
123 */
124 public QName(String namespaceURI, String localPart, String prefix)
125 {
126 this.namespaceURI = (namespaceURI == null)
127 ? emptyString
128 : namespaceURI.intern();
129 if(localPart != null)
130 {
131 this.localPart = localPart.intern();
132 }
133 else
134 {
135 throw new IllegalArgumentException("localpart cannot be null.");
136 }
137 if(prefix != null)
138 {
139 this.prefix = prefix.intern();
140 }
141 else
142 {
143 throw new IllegalArgumentException("prefix cannot be null.");
144 }
145 }
146
147 /**
148 * Gets the Namespace URI for this QName
149 *
150 * @return Namespace URI
151 */
152 public String getNamespaceURI()
153 {
154 return namespaceURI;
155 }
156
157 /**
158 * Gets the Local part for this QName
159 *
160 * @return Local part
161 */
162 public String getLocalPart()
163 {
164 return localPart;
165 }
166
167 /**
168 * Gets the prefix for this QName
169 *
170 * @return prefix of this QName
171 */
172 public String getPrefix()
173 {
174 return prefix;
175 }
176
177 /**
178 * Returns a string representation of this QName
179 *
180 * @return a string representation of the QName
181 */
182 public String toString()
183 {
184 return ((namespaceURI == emptyString)
185 ? localPart
186 : '{' + namespaceURI + '}' + localPart);
187 }
188
189 /**
190 * Tests this QName for equality with another object.
191 * <p>
192 * If the given object is not a QName or is null then this method
193 * returns <tt>false</tt>.
194 * <p>
195 * For two QNames to be considered equal requires that both
196 * localPart and namespaceURI must be equal. This method uses
197 * <code>String.equals</code> to check equality of localPart
198 * and namespaceURI. The prefix is NOT used to determine equality.
199 * Any class that extends QName is required
200 * to satisfy this equality contract.
201 * <p>
202 * This method satisfies the general contract of the <code>Object.equals</code> method.
203 *
204 * @param obj the reference object with which to compare
205 *
206 * @return <code>true</code> if the given object is identical to this
207 * QName: <code>false</code> otherwise.
208 */
209 public final boolean equals(Object obj)
210 {
211 if (obj == this)
212 {
213 return true;
214 }
215
216 if (!(obj instanceof QName))
217 {
218 return false;
219 }
220
221 //We use intern strings, so can use '==' instead of .equals
222 //for better performance.
223
224 if ((namespaceURI == ((QName)obj).namespaceURI)
225 && (localPart == ((QName)obj).localPart))
226 {
227 return true;
228 }
229
230 return false;
231 }
232
233 /**
234 * Returns a QName holding the value of the specified String.
235 * <p>
236 * The string must be in the form returned by the QName.toString()
237 * method, i.e. "{namespaceURI}localPart", with the "{namespaceURI}"
238 * part being optional.
239 * If the Namespace URI .equals(""), only the local part should be
240 * provided.
241 * An empty string "" value will be treated as the localPart.
242 * <p>
243 * The prefix value CANNOT be represented in the String and will be
244 * set to "".
245 * <p>
246 * This method doesn't do a full validation of the resulting QName.
247 * In particular, it doesn't check that the resulting namespace URI
248 * is a legal URI (per RFC 2396 and RFC 2732), nor that the resulting
249 * local part is a legal NCName per the XML Namespaces specification.
250 *
251 * @param s the string to be parsed
252 * @throws java.lang.IllegalArgumentException If the specified String
253 * cannot be parsed as a QName
254 * @return QName corresponding to the given String
255 */
256 public static QName valueOf(String s)
257 {
258 if (s == null)
259 {
260 throw new IllegalArgumentException(
261 "Invalid QName literal - null string.");
262 }
263
264 if(s.indexOf("{") == 0) {
265 int rightBrace = s.indexOf("}");
266 if(rightBrace == -1 || rightBrace == s.length() - 1)
267 {
268 //No matching right brace or no local part after right brace
269 throw new IllegalArgumentException(
270 "Invalid QName literal '" + s + "'.");
271 } else {
272 //namespace and local part
273 return new QName(s.substring(1, rightBrace), s.substring(rightBrace + 1));
274 }
275 } else {
276 //treat the whole string as the local part
277 return new QName(s);
278 }
279 }
280
281 /**
282 * Returns a hash code value for this QName object. The hash code
283 * is based on both the localPart and namespaceURI parts of the
284 * QName. This method satisfies the general contract of the
285 * <code>Object.hashCode</code> method.
286 *
287 * @return a hash code value for this Qname object
288 */
289 public final int hashCode()
290 {
291 return namespaceURI.hashCode() ^ localPart.hashCode();
292 }
293
294 /**
295 * Sets the object variables to internal strings matching the values
296 * from the input stream. If the serialized object represents an
297 * older version of QName that did not support the 'prefix' variable,
298 * then 'prefix' will be set to null by <code>defaultReadObject()</code>.
299 * In this case, change the 'prefix' to the empty string "".
300 *
301 * @param in
302 * @throws IOException
303 * @throws ClassNotFoundException
304 */
305 private void readObject(ObjectInputStream in) throws IOException,
306 ClassNotFoundException
307 {
308 in.defaultReadObject();
309
310 namespaceURI = namespaceURI.intern();
311 localPart = localPart.intern();
312 if(prefix == null)
313 {
314 //The serialized object did not have a 'prefix'.
315 //i.e. it was serialized from an old version of QName.
316 prefix = emptyString;
317 }
318 else
319 {
320 prefix = prefix.intern();
321 }
322 }
323
324 }