001    /*
002     * Common usable utilities
003     *
004     * Copyright (c) 2006 Petr Hadraba <hadrabap@gmail.com>
005     *
006     * Author: Petr Hadraba
007     *
008     * --
009     *
010     * XML Utilities
011     */
012    
013    package global.sandbox.xmlutilities;
014    
015    import java.util.ArrayList;
016    import java.util.Collection;
017    import java.util.Collections;
018    import java.util.Iterator;
019    import java.util.List;
020    import java.util.ListIterator;
021    import java.util.logging.Level;
022    import java.util.logging.Logger;
023    import org.w3c.dom.Node;
024    import org.w3c.dom.NodeList;
025    
026    /**
027     * {@link ArrayList ArrayList} like implementation for {@link NodeList NodeList} which is unmodifiable, not serializable
028     * and exposes access to original {@link NodeList NodeList}. The under-layering implementation is based on a copy,
029     * modifications made to the original {@link NodeList NodeList} have no effect to iterators.
030     *
031     * The name of this class has been chosen in respect to possible collision with {@link NodeList org.w3c.dom.NodeList}
032     * which may occur during import.
033     *
034     * @param <E> element type
035     *
036     * @author Petr Hadraba
037     *
038     * @version 1.2
039     */
040    public class NodeListCollection<E extends Node> implements List<E> {
041    
042        /**
043         * Logger.
044         */
045        private static final Logger LOGGER = Logger.getLogger(XmlUtilities.XMLUTILITIES_LOGGER_NAME);
046    
047        /**
048         * Class type of elements.
049         */
050        private final Class<E> elementType;
051    
052        /**
053         * Original {@link NodeList NodeList}.
054         */
055        private final NodeList nodeList;
056    
057        /**
058         * Unmodifiable implementation.
059         */
060        private final List<E> nodes;
061    
062        /**
063         * Creates new instance from {@link NodeList NodeList}. The under-layering implementation is constant, read only,
064         * unmodifiable. The implementation is intentionally not serializable.
065         *
066         * @param nodeList under-layering {@link NodeList NodeList}
067         * @param elementType class type of element
068         *
069         * @throws XmlUtilitiesException on error (casting, data type conversion)
070         */
071        @SuppressWarnings("unchecked")
072        public NodeListCollection(NodeList nodeList, Class<E> elementType) throws XmlUtilitiesException {
073            this.elementType = elementType;
074            this.nodeList = nodeList;
075    
076            if (nodeList != null && nodeList.getLength() > 0) {
077                List<E> _nodes = new ArrayList<E>();
078                for (int i = 0; i < nodeList.getLength(); i++) {
079                    final Node node = nodeList.item(i);
080                    final E element;
081                    try {
082                        element = elementType.cast(node);
083                    } catch (ClassCastException ex) {
084                        final String message = String.format("Failed to cast element at index %d from %s to %s.", i, node.getClass(), elementType);
085                        LOGGER.log(Level.SEVERE, message, ex);
086                        throw new XmlUtilitiesException(message, ex);
087                    }
088                    _nodes.add(element);
089                }
090                this.nodes = Collections.unmodifiableList(_nodes);
091            } else {
092                this.nodes = Collections.unmodifiableList(Collections.EMPTY_LIST);
093            }
094        }
095    
096        /**
097         * Returns class type of element.
098         *
099         * @return class type of element
100         */
101        public Class<E> getElementType() {
102            return elementType;
103        }
104    
105        /**
106         * Returns under-layering {@link NodeList NodeList}.
107         *
108         * @return under-layering {@link NodeList NodeList}
109         */
110        public NodeList getNodeList() {
111            return nodeList;
112        }
113    
114        /**
115         * {@inheritDoc}
116         */
117        @Override
118        public int size() {
119            return nodes.size();
120        }
121    
122        /**
123         * {@inheritDoc}
124         */
125        @Override
126        public boolean isEmpty() {
127            return nodes.isEmpty();
128        }
129    
130        /**
131         * {@inheritDoc}
132         */
133        @Override
134        public boolean contains(Object o) {
135            return nodes.contains(o);
136        }
137    
138        /**
139         * {@inheritDoc}
140         */
141        @Override
142        public Iterator<E> iterator() {
143            return nodes.iterator();
144        }
145    
146        /**
147         * {@inheritDoc}
148         */
149        @Override
150        public Object[] toArray() {
151            return nodes.toArray();
152        }
153    
154        /**
155         * {@inheritDoc}
156         */
157        @Override
158        public <T> T[] toArray(T[] a) {
159            return nodes.<T>toArray(a);
160        }
161    
162        /**
163         * {@inheritDoc}
164         */
165        @Override
166        public boolean add(E e) {
167            return nodes.add(e);
168        }
169    
170        /**
171         * {@inheritDoc}
172         */
173        @Override
174        public boolean remove(Object o) {
175            return nodes.remove(o);
176        }
177    
178        /**
179         * {@inheritDoc}
180         */
181        @Override
182        public boolean containsAll(Collection<?> c) {
183            return nodes.containsAll(c);
184        }
185    
186        /**
187         * {@inheritDoc}
188         */
189        @Override
190        public boolean addAll(Collection<? extends E> c) {
191            return nodes.addAll(c);
192        }
193    
194        /**
195         * {@inheritDoc}
196         */
197        @Override
198        public boolean addAll(int index, Collection<? extends E> c) {
199            return nodes.addAll(index, c);
200        }
201    
202        /**
203         * {@inheritDoc}
204         */
205        @Override
206        public boolean removeAll(Collection<?> c) {
207            return nodes.removeAll(c);
208        }
209    
210        /**
211         * {@inheritDoc}
212         */
213        @Override
214        public boolean retainAll(Collection<?> c) {
215            return nodes.retainAll(c);
216        }
217    
218        /**
219         * {@inheritDoc}
220         */
221        @Override
222        public void clear() {
223            nodes.clear();
224        }
225    
226        /**
227         * {@inheritDoc}
228         */
229        @Override
230        public E get(int index) {
231            return nodes.get(index);
232        }
233    
234        /**
235         * {@inheritDoc}
236         */
237        @Override
238        public E set(int index, E element) {
239            return nodes.set(index, element);
240        }
241    
242        /**
243         * {@inheritDoc}
244         */
245        @Override
246        public void add(int index, E element) {
247            nodes.add(index, element);
248        }
249    
250        /**
251         * {@inheritDoc}
252         */
253        @Override
254        public E remove(int index) {
255            return nodes.remove(index);
256        }
257    
258        /**
259         * {@inheritDoc}
260         */
261        @Override
262        public int indexOf(Object o) {
263            return nodes.indexOf(o);
264        }
265    
266        /**
267         * {@inheritDoc}
268         */
269        @Override
270        public int lastIndexOf(Object o) {
271            return nodes.lastIndexOf(o);
272        }
273    
274        /**
275         * {@inheritDoc}
276         */
277        @Override
278        public ListIterator<E> listIterator() {
279            return nodes.listIterator();
280        }
281    
282        /**
283         * {@inheritDoc}
284         */
285        @Override
286        public ListIterator<E> listIterator(int index) {
287            return nodes.listIterator(index);
288        }
289    
290        /**
291         * {@inheritDoc}
292         */
293        @Override
294        public List<E> subList(int fromIndex, int toIndex) {
295            return nodes.subList(fromIndex, toIndex);
296        }
297    
298        /**
299         * {@inheritDoc}
300         */
301        @Override
302        public boolean equals(Object obj) {
303            return obj == this || nodes.equals(obj);
304        }
305    
306        /**
307         * {@inheritDoc}
308         */
309        @Override
310        public int hashCode() {
311            return nodes.hashCode();
312        }
313    
314        /**
315         * {@inheritDoc}
316         */
317        @Override
318        public String toString() {
319            return nodes.toString();
320        }
321    
322    }