001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.commons.collections.iterators;
018    
019    import java.util.Iterator;
020    import java.util.Map;
021    
022    import org.apache.commons.collections.MapIterator;
023    import org.apache.commons.collections.ResettableIterator;
024    
025    /**
026     * Implements a <code>MapIterator</code> using a Map entrySet.
027     * Reverse iteration is not supported.
028     * <pre>
029     * MapIterator it = map.mapIterator();
030     * while (it.hasNext()) {
031     *   Object key = it.next();
032     *   Object value = it.getValue();
033     *   it.setValue(newValue);
034     * }
035     * </pre>
036     *  
037     * @since Commons Collections 3.0
038     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
039     *
040     * @author Stephen Colebourne
041     */
042    public class EntrySetMapIterator implements MapIterator, ResettableIterator {
043        
044        private final Map map;
045        private Iterator iterator;
046        private Map.Entry last;
047        private boolean canRemove = false;
048        
049        /**
050         * Constructor.
051         * 
052         * @param map  the map to iterate over
053         */
054        public EntrySetMapIterator(Map map) {
055            super();
056            this.map = map;
057            this.iterator = map.entrySet().iterator();
058        }
059    
060        //-----------------------------------------------------------------------    
061        /**
062         * Checks to see if there are more entries still to be iterated.
063         *
064         * @return <code>true</code> if the iterator has more elements
065         */
066        public boolean hasNext() {
067            return iterator.hasNext();
068        }
069    
070        /**
071         * Gets the next <em>key</em> from the <code>Map</code>.
072         *
073         * @return the next key in the iteration
074         * @throws java.util.NoSuchElementException if the iteration is finished
075         */
076        public Object next() {
077            last = (Map.Entry) iterator.next();
078            canRemove = true;
079            return last.getKey();
080        }
081    
082        //-----------------------------------------------------------------------
083        /**
084         * Removes the last returned key from the underlying <code>Map</code>.
085         * <p>
086         * This method can be called once per call to <code>next()</code>.
087         *
088         * @throws UnsupportedOperationException if remove is not supported by the map
089         * @throws IllegalStateException if <code>next()</code> has not yet been called
090         * @throws IllegalStateException if <code>remove()</code> has already been called
091         *  since the last call to <code>next()</code>
092         */
093        public void remove() {
094            if (canRemove == false) {
095                throw new IllegalStateException("Iterator remove() can only be called once after next()");
096            }
097            iterator.remove();
098            last = null;
099            canRemove = false;
100        }
101        
102        //-----------------------------------------------------------------------
103        /**
104         * Gets the current key, which is the key returned by the last call
105         * to <code>next()</code>.
106         *
107         * @return the current key
108         * @throws IllegalStateException if <code>next()</code> has not yet been called
109         */
110        public Object getKey() {
111            if (last == null) {
112                throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()");
113            }
114            return last.getKey();
115        }
116    
117        /**
118         * Gets the current value, which is the value associated with the last key
119         * returned by <code>next()</code>.
120         *
121         * @return the current value
122         * @throws IllegalStateException if <code>next()</code> has not yet been called
123         */
124        public Object getValue() {
125            if (last == null) {
126                throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()");
127            }
128            return last.getValue();
129        }
130    
131        /**
132         * Sets the value associated with the current key.
133         *
134         * @param value  the new value
135         * @return the previous value
136         * @throws UnsupportedOperationException if setValue is not supported by the map
137         * @throws IllegalStateException if <code>next()</code> has not yet been called
138         * @throws IllegalStateException if <code>remove()</code> has been called since the
139         *  last call to <code>next()</code>
140         */
141        public Object setValue(Object value) {
142            if (last == null) {
143                throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()");
144            }
145            return last.setValue(value);
146        }
147    
148        //-----------------------------------------------------------------------
149        /**
150         * Resets the state of the iterator.
151         */
152        public void reset() {
153            iterator = map.entrySet().iterator();
154            last = null;
155            canRemove = false;
156        }
157        
158        /**
159         * Gets the iterator as a String.
160         * 
161         * @return a string version of the iterator
162         */    
163        public String toString() {
164            if (last != null) {
165                return "MapIterator[" + getKey() + "=" + getValue() + "]";
166            } else {
167                return "MapIterator[]";
168            }
169        }
170        
171    }