001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package javax.xml.namespace;
021
022 import java.io.IOException;
023 import java.io.ObjectInputStream;
024 import java.io.Serializable;
025
026 /**
027 * <code>QName</code> class represents the value of a qualified name
028 * as specified in <a href="http://www.w3.org/TR/xmlschema-2/#QName">XML
029 * Schema Part2: Datatypes specification</a>.
030 * <p>
031 * The value of a QName contains a <b>namespaceURI</b>, a <b>localPart</b> and a
032 * <b>prefix</b>. The localPart provides the local part of the qualified name.
033 * The namespaceURI is a URI reference identifying the namespace.
034 *
035 * @version 1.1
036 */
037 public class QName implements Serializable {
038
039 /** Comment/shared empty <code>String</code>. */
040 private static final String emptyString = "".intern();
041
042 private String namespaceURI;
043
044 private String localPart;
045
046 private String prefix;
047
048 /**
049 * Constructor for the QName.
050 *
051 * @param localPart local part of the QName
052 */
053 public QName(String localPart) {
054 this(emptyString, localPart, emptyString);
055 }
056
057 /**
058 * Constructor for the QName.
059 *
060 * @param namespaceURI namespace URI for the QName
061 * @param localPart local part of the QName.
062 */
063 public QName(String namespaceURI, String localPart) {
064 this(namespaceURI, localPart, emptyString);
065 }
066
067 /**
068 * Constructor for the QName.
069 *
070 * @param namespaceURI Namespace URI for the QName
071 * @param localPart Local part of the QName.
072 * @param prefix Prefix of the QName.
073 */
074 public QName(String namespaceURI, String localPart, String prefix) {
075 this.namespaceURI = (namespaceURI == null)
076 ? emptyString
077 : namespaceURI.intern();
078 if (localPart == null) {
079 throw new IllegalArgumentException("invalid QName local part");
080 } else {
081 this.localPart = localPart.intern();
082 }
083
084 if (prefix == null) {
085 throw new IllegalArgumentException("invalid QName prefix");
086 } else {
087 this.prefix = prefix.intern();
088 }
089 }
090
091 /**
092 * Gets the namespace URI for this QName.
093 *
094 * @return namespace URI
095 */
096 public String getNamespaceURI() {
097 return namespaceURI;
098 }
099
100 /**
101 * Gets the local part for this QName.
102 *
103 * @return the local part
104 */
105 public String getLocalPart() {
106 return localPart;
107 }
108
109 /**
110 * Gets the prefix for this QName.
111 *
112 * @return the prefix
113 */
114 public String getPrefix() {
115 return prefix;
116 }
117
118 /**
119 * Returns a string representation of this QName.
120 *
121 * @return a string representation of the QName
122 */
123 public String toString() {
124
125 return ((namespaceURI == emptyString)
126 ? localPart
127 : '{' + namespaceURI + '}' + localPart);
128 }
129
130 /**
131 * Tests this QName for equality with another object.
132 * <p>
133 * If the given object is not a QName or is null then this method
134 * returns <tt>false</tt>.
135 * <p>
136 * For two QNames to be considered equal requires that both
137 * localPart and namespaceURI must be equal. This method uses
138 * <code>String.equals</code> to check equality of localPart
139 * and namespaceURI. Any class that extends QName is required
140 * to satisfy this equality contract.
141 * <p>
142 * This method satisfies the general contract of the <code>Object.equals</code> method.
143 *
144 * @param obj the reference object with which to compare
145 *
146 * @return <code>true</code> if the given object is identical to this
147 * QName: <code>false</code> otherwise.
148 */
149 public final boolean equals(Object obj) {
150
151 if (obj == this) {
152 return true;
153 }
154
155 if (!(obj instanceof QName)) {
156 return false;
157 }
158
159 if ((namespaceURI == ((QName) obj).namespaceURI)
160 && (localPart == ((QName) obj).localPart)) {
161 return true;
162 }
163
164 return false;
165 }
166
167 /**
168 * Returns a QName holding the value of the specified String.
169 * <p>
170 * The string must be in the form returned by the QName.toString()
171 * method, i.e. "{namespaceURI}localPart", with the "{namespaceURI}"
172 * part being optional.
173 * <p>
174 * This method doesn't do a full validation of the resulting QName.
175 * In particular, it doesn't check that the resulting namespace URI
176 * is a legal URI (per RFC 2396 and RFC 2732), nor that the resulting
177 * local part is a legal NCName per the XML Namespaces specification.
178 *
179 * @param s the string to be parsed
180 * @throws java.lang.IllegalArgumentException If the specified String cannot be parsed as a QName
181 * @return QName corresponding to the given String
182 */
183 public static QName valueOf(String s) {
184
185 if ((s == null) || s.equals("")) {
186 throw new IllegalArgumentException("invalid QName literal");
187 }
188
189 if (s.charAt(0) == '{') {
190 int i = s.indexOf('}');
191
192 if (i == -1) {
193 throw new IllegalArgumentException("invalid QName literal");
194 }
195
196 if (i == s.length() - 1) {
197 throw new IllegalArgumentException("invalid QName literal");
198 } else {
199 return new QName(s.substring(1, i), s.substring(i + 1));
200 }
201 } else {
202 return new QName(s);
203 }
204 }
205
206 /**
207 * Returns a hash code value for this QName object. The hash code
208 * is based on both the localPart and namespaceURI parts of the
209 * QName. This method satisfies the general contract of the
210 * <code>Object.hashCode</code> method.
211 *
212 * @return a hash code value for this Qname object
213 */
214 public final int hashCode() {
215 return namespaceURI.hashCode() ^ localPart.hashCode();
216 }
217
218 /**
219 * Ensure that deserialization properly interns the results.
220 * @param in the ObjectInputStream to be read
221 * @throws IOException if there was a failure in the object input stream
222 * @throws ClassNotFoundException if the class of any sub-objects could
223 * not be found
224 */
225 private void readObject(ObjectInputStream in) throws
226 IOException, ClassNotFoundException {
227 in.defaultReadObject();
228
229 namespaceURI = namespaceURI.intern();
230 localPart = localPart.intern();
231 prefix = prefix.intern();
232 }
233 }