001/* ========================================================================
002 * JCommon : a free general purpose class library for the Java(tm) platform
003 * ========================================================================
004 *
005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006 * 
007 * Project Info:  http://www.jfree.org/jcommon/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it 
010 * under the terms of the GNU Lesser General Public License as published by 
011 * the Free Software Foundation; either version 2.1 of the License, or 
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but 
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022 * USA.  
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025 * in the United States and other countries.]
026 * 
027 * ------------------
028 * AttributeList.java
029 * ------------------
030 * (C)opyright 2003-2005, by Thomas Morgner and Contributors.
031 *
032 * Original Author:  Thomas Morgner;
033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
034 *
035 * $Id: AttributeList.java,v 1.3 2005/10/18 13:35:06 mungady Exp $
036 *
037 * Changes
038 * -------
039 * 25-Sep-2003 : Initial version (TM);
040 * 26-Nov-2003 : Javadoc updates (DG);
041 *
042 */
043
044package org.jfree.xml.writer;
045
046import java.util.Iterator;
047import java.util.List;
048
049/**
050 * The attribute list is used by a writer to specify the attributes
051 * of an XML element in a certain order.
052 *
053 * @author Thomas Morgner
054 */
055public class AttributeList {
056
057    /**
058     * A name/value pair of the attribute list.
059     */
060    private static class AttributeEntry {
061        
062        /** The name of the attribute entry. */
063        private String name;
064        
065        /** The value of the attribute entry. */
066        private String value;
067
068        /**
069         * Creates a new attribute entry for the given name and value.
070         *
071         * @param name  the attribute name (<code>null</code> not permitted).
072         * @param value the attribute value (<code>null</code> not permitted).
073         */
074        public AttributeEntry(final String name, final String value) {
075            if (name == null) {
076                throw new NullPointerException("Name must not be null. [" 
077                                               + name + ", " + value + "]");
078            }
079            if (value == null) {
080                throw new NullPointerException("Value must not be null. [" 
081                                               + name + ", " + value + "]");
082            }
083            this.name = name;
084            this.value = value;
085        }
086
087        /**
088         * Returns the attribute name.
089         * 
090         * @return the name.
091         */
092        public String getName() {
093            return this.name;
094        }
095
096        /**
097         * Returns the value of this attribute entry.
098         * 
099         * @return the value of the entry.
100         */
101        public String getValue() {
102            return this.value;
103        }
104
105        /**
106         * Checks whether the given object is an attribute entry with the same name.
107         * 
108         * @param o  the suspected other attribute entry.
109         * 
110         * @return <code>true</code> if the given object is equal, <code>false</code> otherwise.
111         */
112        public boolean equals(final Object o) {
113            if (this == o) {
114                return true;
115            }
116            if (!(o instanceof AttributeEntry)) {
117                return false;
118            }
119
120            final AttributeEntry attributeEntry = (AttributeEntry) o;
121            if (!this.name.equals(attributeEntry.name)) {
122                return false;
123            }
124            return true;
125        }
126
127        /**
128         * Computes an hashcode for this entry.
129         * 
130         * @return the hashcode.
131         */
132        public int hashCode() {
133            return this.name.hashCode();
134        }
135    }
136
137    /**
138     * An iterator over the attribute names of this list.
139     */
140    private static class AttributeIterator implements Iterator {
141        
142        /** The backend is an iterator over the attribute entries. */
143        private Iterator backend;
144
145        /**
146         * Creates a new attribute iterator using the given iterator as backend.
147         * 
148         * @param backend  an iterator over the attribute entries (<code>null</code> not permitted).
149         */
150        public AttributeIterator(final Iterator backend) {
151            if (backend == null) {
152                throw new NullPointerException();
153            }
154            this.backend = backend;
155        }
156
157        /**
158         * Returns <tt>true</tt> if the iteration has more elements. (In other
159         * words, returns <tt>true</tt> if <tt>next</tt> would return an element
160         * rather than throwing an exception.)
161         *
162         * @return <tt>true</tt> if the iterator has more elements.
163         */
164        public boolean hasNext() {
165            return this.backend.hasNext();
166        }
167
168        /**
169         * Returns the next element in the iteration.
170         *
171         * @return the next element in the iteration.
172         */
173        public Object next() {
174            final AttributeEntry entry = (AttributeEntry) this.backend.next();
175            if (entry != null) {
176                return entry.getName();
177            }
178            return entry;
179        }
180
181        /**
182         *
183         * Removes from the underlying collection the last element returned by the
184         * iterator (optional operation).  This method can be called only once per
185         * call to <tt>next</tt>.  The behavior of an iterator is unspecified if
186         * the underlying collection is modified while the iteration is in
187         * progress in any way other than by calling this method.
188         */
189        public void remove() {
190            this.backend.remove();
191        }
192    }
193
194    /** The storage for all entries of this list. */
195    private List entryList;
196
197    /**
198     * Creates an empty attribute list with no default values.
199     */
200    public AttributeList() {
201        this.entryList = new java.util.ArrayList();
202    }
203
204    /**
205     * Returns an iterator over all attribute names. The names are returned
206     * in their oder of addition to the list. The iterator contains strings.
207     *
208     * @return the iterator over all attribute names.
209     */
210    public Iterator keys() {
211        return new AttributeIterator(this.entryList.iterator());
212    }
213
214    /**
215     * Defines an attribute.
216     * 
217     * @param name the name of the attribute to be defined
218     * @param value the value of the attribute.
219     */
220    public synchronized void setAttribute(final String name, final String value) {
221        final AttributeEntry entry = new AttributeEntry(name, value);
222        final int pos = this.entryList.indexOf(entry);
223        if (pos != -1) {
224            this.entryList.remove(pos);
225        }
226        this.entryList.add(entry);
227    }
228
229    /**
230     * Returns the attribute value for the given attribute name or null,
231     * if the attribute is not defined in this list.
232     *
233     * @param name the name of the attribute
234     * @return the attribute value or null.
235     */
236    public synchronized String getAttribute(final String name) {
237        return getAttribute(name, null);
238    }
239
240    /**
241     * Returns the attribute value for the given attribute name or the given
242     * defaultvalue, if the attribute is not defined in this list.
243     *
244     * @param name the name of the attribute.
245     * @param defaultValue  the default value.
246     * 
247     * @return the attribute value or the defaultValue.
248     */
249    public synchronized String getAttribute(final String name, final String defaultValue) {
250        for (int i = 0; i < this.entryList.size(); i++) {
251            final AttributeEntry ae = (AttributeEntry) this.entryList.get(i);
252            if (ae.getName().equals(name)) {
253                return ae.getValue();
254            }
255        }
256        return defaultValue;
257    }
258
259    /**
260     * Removes the attribute with the given name from the list.
261     *
262     * @param name the name of the attribute which should be removed..
263     */
264    public synchronized void removeAttribute(final String name) {
265        for (int i = 0; i < this.entryList.size(); i++) {
266            final AttributeEntry ae = (AttributeEntry) this.entryList.get(i);
267            if (ae.getName().equals(name)) {
268                this.entryList.remove(ae);
269                return;
270            }
271        }
272    }
273}