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 as specified in <a
028: * href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2: Datatypes specification</a>.
029: * <p/>
030: * The value of a QName contains a <b>namespaceURI</b>, a <b>localPart</b> and a <b>prefix</b>. The
031: * localPart provides the local part of the qualified name. The namespaceURI is a URI reference
032: * identifying the namespace.
033: *
034: * @version 1.1
035: */
036: public class QName implements Serializable {
037:
038: private static final long serialVersionUID = -6756054858541526837L;
039:
040: /** Comment/shared empty <code>String</code>. */
041: private static final String emptyString = "".intern();
042:
043: private String namespaceURI;
044:
045: private String localPart;
046:
047: private String prefix;
048:
049: /**
050: * Constructor for the QName.
051: *
052: * @param localPart local part of the QName
053: */
054: public QName(String localPart) {
055: this (emptyString, localPart, emptyString);
056: }
057:
058: /**
059: * Constructor for the QName.
060: *
061: * @param namespaceURI namespace URI for the QName
062: * @param localPart local part of the QName.
063: */
064: public QName(String namespaceURI, String localPart) {
065: this (namespaceURI, localPart, emptyString);
066: }
067:
068: /**
069: * Constructor for the QName.
070: *
071: * @param namespaceURI Namespace URI for the QName
072: * @param localPart Local part of the QName.
073: * @param prefix Prefix of the QName.
074: */
075: public QName(String namespaceURI, String localPart, String prefix) {
076: this .namespaceURI = (namespaceURI == null) ? emptyString
077: : namespaceURI.intern();
078: if (localPart == null) {
079: throw new IllegalArgumentException(
080: "invalid QName local part");
081: } else {
082: this .localPart = localPart.intern();
083: }
084:
085: if (prefix == null) {
086: throw new IllegalArgumentException("invalid QName prefix");
087: } else {
088: this .prefix = prefix.intern();
089: }
090: }
091:
092: /**
093: * Gets the namespace URI for this QName.
094: *
095: * @return namespace URI
096: */
097: public String getNamespaceURI() {
098: return namespaceURI;
099: }
100:
101: /**
102: * Gets the local part for this QName.
103: *
104: * @return the local part
105: */
106: public String getLocalPart() {
107: return localPart;
108: }
109:
110: /**
111: * Gets the prefix for this QName.
112: *
113: * @return the prefix
114: */
115: public String getPrefix() {
116: return prefix;
117: }
118:
119: /**
120: * Returns a string representation of this QName.
121: *
122: * @return a string representation of the QName
123: */
124: public String toString() {
125:
126: return ((namespaceURI == emptyString) ? 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 returns <tt>false</tt>.
134: * <p/>
135: * For two QNames to be considered equal requires that both localPart and namespaceURI must be
136: * equal. This method uses <code>String.equals</code> to check equality of localPart and
137: * namespaceURI. Any class that extends QName is required to satisfy this equality contract.
138: * <p/>
139: * This method satisfies the general contract of the <code>Object.equals</code> method.
140: *
141: * @param obj the reference object with which to compare
142: * @return <code>true</code> if the given object is identical to this QName: <code>false</code>
143: * otherwise.
144: */
145: public boolean equals(Object obj) {
146:
147: if (obj == this ) {
148: return true;
149: }
150:
151: if (!(obj instanceof QName)) {
152: return false;
153: }
154:
155: return (namespaceURI.equals(((QName) obj).namespaceURI))
156: && (localPart.equals(((QName) obj).localPart));
157:
158: }
159:
160: /**
161: * Returns a QName holding the value of the specified String.
162: * <p/>
163: * The string must be in the form returned by the QName.toString() method, i.e.
164: * "{namespaceURI}localPart", with the "{namespaceURI}" part being optional.
165: * <p/>
166: * This method doesn't do a full validation of the resulting QName. In particular, it doesn't
167: * check that the resulting namespace URI is a legal URI (per RFC 2396 and RFC 2732), nor that
168: * the resulting local part is a legal NCName per the XML Namespaces specification.
169: *
170: * @param s the string to be parsed
171: * @return QName corresponding to the given String
172: * @throws IllegalArgumentException
173: * If the specified String cannot be parsed as a QName
174: */
175: public static QName valueOf(String s) {
176:
177: if ((s == null) || "".equals(s)) {
178: throw new IllegalArgumentException("invalid QName literal");
179: }
180:
181: if (s.charAt(0) == '{') {
182: int i = s.indexOf('}');
183:
184: if (i == -1) {
185: throw new IllegalArgumentException(
186: "invalid QName literal");
187: }
188:
189: if (i == s.length() - 1) {
190: throw new IllegalArgumentException(
191: "invalid QName literal");
192: } else {
193: return new QName(s.substring(1, i), s.substring(i + 1));
194: }
195: } else {
196: return new QName(s);
197: }
198: }
199:
200: /**
201: * Returns a hash code value for this QName object. The hash code is based on both the localPart
202: * and namespaceURI parts of the QName. This method satisfies the general contract of the
203: * <code>Object.hashCode</code> method.
204: *
205: * @return a hash code value for this Qname object
206: */
207: public int hashCode() {
208: return namespaceURI.hashCode() ^ localPart.hashCode();
209: }
210:
211: /**
212: * Ensure that deserialization properly interns the results.
213: *
214: * @param in the ObjectInputStream to be read
215: * @throws IOException if there was a failure in the object input stream
216: * @throws ClassNotFoundException if the class of any sub-objects could not be found
217: */
218: private void readObject(ObjectInputStream in) throws IOException,
219: ClassNotFoundException {
220: in.defaultReadObject();
221:
222: namespaceURI = namespaceURI.intern();
223: localPart = localPart.intern();
224: prefix = prefix.intern();
225: }
226: }
|