001/*
002 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
003 * 
004 * This software is open source. 
005 * See the bottom of this file for the licence.
006 * 
007 * $Id: QName.java,v 1.9 2001/08/15 12:02:00 jstrachan Exp $
008 */
009
010package org.dom4j;
011
012import java.io.IOException;
013import java.io.Serializable;
014import java.io.ObjectInputStream;
015import java.io.ObjectOutputStream;
016
017import org.dom4j.tree.QNameCache;
018
019/** <p><code>QName</code> represents a qualified name value of an XML element 
020  * or attribute. It consists of a local name and a {@link Namespace} 
021  * instance. This object is immutable.</p>
022  *
023  * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
024  * @version $Revision: 1.9 $
025  */
026public class QName implements Serializable {
027
028    protected transient static QNameCache cache = new QNameCache();
029    
030    
031    /** The local name of the element or attribute */
032    private String name;
033    
034    /** The qualified name of the element or attribute */
035    private String qualifiedName;
036    
037    /** The Namespace of this element or attribute */
038    private transient Namespace namespace;
039    
040    /** A cached version of the hashcode for efficiency */
041    private int hashCode;
042    
043    /** The document factory used for this QName if specified or null */
044    private DocumentFactory documentFactory;
045
046    
047    public static synchronized QName get(String name) {
048        return cache.get(name);
049    }
050    
051    public static synchronized QName get(String name, Namespace namespace) {
052        return cache.get(name, namespace);
053    }
054    
055    public static synchronized QName get(String name, String prefix, String uri) {
056        return cache.get(name, Namespace.get( prefix, uri ));
057    }
058    
059    public static synchronized QName get(String qualifiedName, String uri) {
060        return cache.get(qualifiedName, uri);
061    }
062    
063    public static synchronized QName get(String localName, Namespace namespace, String qualifiedName) {
064        return cache.get(localName, namespace, qualifiedName);
065    }
066    
067    public QName(String name) {
068        this( name, Namespace.NO_NAMESPACE );
069    }
070    
071    public QName(String name, Namespace namespace) {
072        this.name = (name == null) ? "" : name;
073        this.namespace = (namespace == null) ? Namespace.NO_NAMESPACE : namespace;
074    }
075
076    public QName(String name, Namespace namespace, String qualifiedName) {
077        this.name = (name == null) ? "" : name;
078        this.qualifiedName = qualifiedName;
079        this.namespace = (namespace == null) ? Namespace.NO_NAMESPACE : namespace;
080    }
081
082    
083    /** @return the local name
084      */
085    public String getName() {
086        return name;
087    }
088    
089    /** @return the qualified name in the format <code>prefix:localName</code>
090      */
091    public String getQualifiedName() {
092        if ( qualifiedName == null ) {
093            String prefix = getNamespacePrefix();
094            if ( prefix != null && prefix.length() > 0 ) {
095                qualifiedName = prefix + ":" + name;
096            }
097            else {
098                qualifiedName = name;
099            }
100        }
101        return qualifiedName;
102    }
103    
104    /** @return the namespace of this QName 
105      */
106    public Namespace getNamespace() {
107        return namespace;
108    }
109        
110    /** @return the namespace URI of this QName
111      */
112    public String getNamespacePrefix() {
113        if ( namespace == null ) {
114            return "";
115        }
116        return namespace.getPrefix();
117    }
118        
119    /** @return the namespace URI of this QName
120      */
121    public String getNamespaceURI() {
122        if ( namespace == null ) {
123            return "";
124        }
125        return namespace.getURI();
126    }
127        
128    
129    /** @return the hash code based on the qualified name and the URI of the 
130      * namespace.
131      */
132    public int hashCode() {
133        if ( hashCode == 0 ) {
134            hashCode = getName().hashCode() 
135                ^ getNamespaceURI().hashCode();
136            if ( hashCode == 0 ) {
137                hashCode = 0xbabe;
138            }
139        }
140        return hashCode;
141    }
142  
143    public boolean equals(Object object) {
144        if ( this == object ) {
145            return true;
146        }
147        else if ( object instanceof QName ) {
148            QName that = (QName) object;
149            // we cache hash codes so this should be quick
150            if ( hashCode() == that.hashCode() ) {
151                return getName().equals( that.getName() )
152                    && getNamespaceURI().equals( that.getNamespaceURI());
153            }
154        }
155        return false;
156    }
157    
158    public String toString() {
159        return super.toString() + " [name: " + getName() 
160            + " namespace: \"" + getNamespace() + "\"]";
161    }
162
163    /** @return the factory that should be used for Elements of this QName */
164    public DocumentFactory getDocumentFactory() {
165        return documentFactory;
166    }
167
168    public void setDocumentFactory(DocumentFactory documentFactory) {
169        this.documentFactory = documentFactory;
170    }
171    
172    private void writeObject(ObjectOutputStream out) throws IOException {
173
174        // We use writeObject() and not writeUTF() to minimize space
175        // This allows for writing pointers to already written strings
176        out.writeObject(namespace.getPrefix());
177        out.writeObject(namespace.getURI());
178        
179        out.defaultWriteObject();
180    }
181        
182    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
183        
184        String prefix = (String) in.readObject();
185        String uri = (String) in.readObject();
186        
187        in.defaultReadObject();
188
189        namespace = Namespace.get( prefix, uri );
190    }
191
192
193}
194
195
196
197
198/*
199 * Redistribution and use of this software and associated documentation
200 * ("Software"), with or without modification, are permitted provided
201 * that the following conditions are met:
202 *
203 * 1. Redistributions of source code must retain copyright
204 *    statements and notices.  Redistributions must also contain a
205 *    copy of this document.
206 *
207 * 2. Redistributions in binary form must reproduce the
208 *    above copyright notice, this list of conditions and the
209 *    following disclaimer in the documentation and/or other
210 *    materials provided with the distribution.
211 *
212 * 3. The name "DOM4J" must not be used to endorse or promote
213 *    products derived from this Software without prior written
214 *    permission of MetaStuff, Ltd.  For written permission,
215 *    please contact dom4j-info@metastuff.com.
216 *
217 * 4. Products derived from this Software may not be called "DOM4J"
218 *    nor may "DOM4J" appear in their names without prior written
219 *    permission of MetaStuff, Ltd. DOM4J is a registered
220 *    trademark of MetaStuff, Ltd.
221 *
222 * 5. Due credit should be given to the DOM4J Project
223 *    (http://dom4j.org/).
224 *
225 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
226 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
227 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
228 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
229 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
230 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
231 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
232 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
234 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
235 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
236 * OF THE POSSIBILITY OF SUCH DAMAGE.
237 *
238 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
239 *
240 * $Id: QName.java,v 1.9 2001/08/15 12:02:00 jstrachan Exp $
241 */