001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006    * See the AUTHORS.txt file in the distribution for a full listing of 
007    * individual contributors.
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.graph.property.basic;
025    
026    import net.jcip.annotations.Immutable;
027    import org.jboss.dna.common.text.TextEncoder;
028    import org.jboss.dna.common.util.CheckArg;
029    import org.jboss.dna.common.util.HashCode;
030    import org.jboss.dna.graph.property.Name;
031    import org.jboss.dna.graph.property.NamespaceRegistry;
032    import org.jboss.dna.graph.property.Path;
033    
034    /**
035     * A basic implementation of {@link Name}.
036     * 
037     * @author Randall Hauch
038     * @author John Verhaeg
039     */
040    @Immutable
041    public class BasicName implements Name {
042    
043        private String trimNonEmptyStrings( String value ) {
044            if (value == null) return null;
045            String trimmed = value.trim();
046            return trimmed.length() == 0 ? value : trimmed;
047        }
048    
049        /**
050         */
051        private static final long serialVersionUID = -1737537720336990144L;
052        private final String namespaceUri;
053        private final String localName;
054        private final int hc;
055    
056        public BasicName( String namespaceUri,
057                          String localName ) {
058            CheckArg.isNotEmpty(localName, "localName");
059            this.namespaceUri = namespaceUri != null ? namespaceUri.trim().intern() : "";
060            this.localName = trimNonEmptyStrings(localName);
061            this.hc = HashCode.compute(this.namespaceUri, this.localName);
062        }
063    
064        /**
065         * {@inheritDoc}
066         */
067        public String getLocalName() {
068            return this.localName;
069        }
070    
071        /**
072         * {@inheritDoc}
073         */
074        public String getNamespaceUri() {
075            return this.namespaceUri;
076        }
077    
078        /**
079         * {@inheritDoc}
080         */
081        public String getString() {
082            return getString(Path.DEFAULT_ENCODER);
083        }
084    
085        /**
086         * {@inheritDoc}
087         */
088        public String getString( TextEncoder encoder ) {
089            if (this.getNamespaceUri().length() == 0) {
090                if (this.getLocalName().equals(Path.SELF)) return Path.SELF;
091                if (this.getLocalName().equals(Path.PARENT)) return Path.PARENT;
092            }
093            if (encoder == null) encoder = Path.DEFAULT_ENCODER;
094            
095            if (namespaceUri.length() > 0) {
096                return "{" + encoder.encode(this.namespaceUri) + "}" + encoder.encode(this.localName);
097            }
098            return encoder.encode(this.localName);
099        }
100    
101        /**
102         * {@inheritDoc}
103         */
104        public String getString( NamespaceRegistry namespaceRegistry ) {
105            CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
106            String prefix = namespaceRegistry.getPrefixForNamespaceUri(this.namespaceUri, true);
107            if (prefix != null && prefix.length() != 0) {
108                return prefix + ":" + this.localName;
109            }
110            return this.localName;
111        }
112    
113        /**
114         * {@inheritDoc}
115         */
116        public String getString( NamespaceRegistry namespaceRegistry,
117                                 TextEncoder encoder ) {
118            // This is the most-often used method, so implement it directly
119            CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
120            String prefix = namespaceRegistry.getPrefixForNamespaceUri(this.namespaceUri, true);
121            if (prefix != null && prefix.length() != 0) {
122                return encoder.encode(prefix) + ":" + encoder.encode(this.localName);
123            }
124            return encoder.encode(this.localName);
125        }
126    
127        /**
128         * {@inheritDoc}
129         * 
130         * @see org.jboss.dna.graph.property.Name#getString(org.jboss.dna.graph.property.NamespaceRegistry,
131         *      org.jboss.dna.common.text.TextEncoder, org.jboss.dna.common.text.TextEncoder)
132         */
133        public String getString( NamespaceRegistry namespaceRegistry,
134                                 TextEncoder encoder,
135                                 TextEncoder delimiterEncoder ) {
136            if (namespaceRegistry == null) {
137                if (this.getNamespaceUri().length() == 0) {
138                    if (this.getLocalName().equals(Path.SELF)) return Path.SELF;
139                    if (this.getLocalName().equals(Path.PARENT)) return Path.PARENT;
140                }
141                if (encoder == null) encoder = Path.DEFAULT_ENCODER;
142                if (delimiterEncoder != null) {
143                    return delimiterEncoder.encode("{") + encoder.encode(this.namespaceUri) + delimiterEncoder.encode("}")
144                           + encoder.encode(this.localName);
145                }
146                return "{" + encoder.encode(this.namespaceUri) + "}" + encoder.encode(this.localName);
147    
148            }
149            if (encoder == null) encoder = Path.DEFAULT_ENCODER;
150            String prefix = namespaceRegistry.getPrefixForNamespaceUri(this.namespaceUri, true);
151            if (prefix != null && prefix.length() != 0) {
152                String delim = delimiterEncoder != null ? delimiterEncoder.encode(":") : ":";
153                return encoder.encode(prefix) + delim + encoder.encode(this.localName);
154            }
155            return encoder.encode(this.localName);
156        }
157    
158        /**
159         * {@inheritDoc}
160         */
161        public int compareTo( Name that ) {
162            if (that == this) return 0;
163            int diff = this.getLocalName().compareTo(that.getLocalName());
164            if (diff != 0) return diff;
165            diff = this.getNamespaceUri().compareTo(that.getNamespaceUri());
166            return diff;
167        }
168    
169        /**
170         * {@inheritDoc}
171         */
172        @Override
173        public int hashCode() {
174            return this.hc;
175        }
176    
177        /**
178         * {@inheritDoc}
179         */
180        @Override
181        public boolean equals( Object obj ) {
182            if (obj == this) return true;
183            if (obj instanceof Name) {
184                Name that = (Name)obj;
185                if (!this.getLocalName().equals(that.getLocalName())) return false;
186                if (!this.getNamespaceUri().equals(that.getNamespaceUri())) return false;
187                return true;
188            }
189            return false;
190        }
191    
192        /**
193         * {@inheritDoc}
194         */
195        @Override
196        public String toString() {
197            return "{" + this.namespaceUri + "}" + this.localName;
198        }
199    
200    }