001    package railo.runtime.text.xml;
002    
003    import java.util.ArrayList;
004    import java.util.Comparator;
005    import java.util.Iterator;
006    import java.util.List;
007    import java.util.Map.Entry;
008    
009    import org.w3c.dom.Document;
010    import org.w3c.dom.Node;
011    import org.w3c.dom.NodeList;
012    
013    import railo.runtime.PageContext;
014    import railo.runtime.dump.DumpData;
015    import railo.runtime.dump.DumpProperties;
016    import railo.runtime.dump.DumpTable;
017    import railo.runtime.dump.DumpUtil;
018    import railo.runtime.dump.SimpleDumpData;
019    import railo.runtime.exp.ExpressionException;
020    import railo.runtime.exp.PageException;
021    import railo.runtime.op.Caster;
022    import railo.runtime.text.xml.struct.XMLObject;
023    import railo.runtime.text.xml.struct.XMLStruct;
024    import railo.runtime.type.Collection;
025    import railo.runtime.type.KeyImpl;
026    import railo.runtime.type.dt.DateTime;
027    import railo.runtime.type.it.EntryIterator;
028    import railo.runtime.type.it.KeyIterator;
029    import railo.runtime.type.it.StringIterator;
030    import railo.runtime.type.util.ArraySupport;
031    import railo.runtime.type.util.ArrayUtil;
032    import railo.runtime.util.ArrayIterator;
033    
034    /**
035     * 
036     */
037    public final class XMLNodeList extends ArraySupport implements NodeList, XMLObject{
038    
039            private boolean caseSensitive;
040            private Document doc;
041            private Node parent;
042            private String filter;
043            
044            /**
045             * @param parent Parent Node
046             * @param caseSensitive
047             */
048        public XMLNodeList(Node parent, boolean caseSensitive) {
049            this(parent,caseSensitive,null);
050        }
051        public XMLNodeList(Node parent, boolean caseSensitive, String filter) {
052            if(parent instanceof XMLStruct) {
053                XMLStruct xmlNode = ((XMLStruct)parent);
054                this.parent=xmlNode.toNode();
055                this.caseSensitive=xmlNode.getCaseSensitive();
056            }
057            else {
058                this.parent=parent;
059                this.caseSensitive=caseSensitive;
060            }
061            this.doc=this.parent.getOwnerDocument();
062            this.filter=filter;
063        }
064    
065            @Override
066            public int getLength() {
067                    return XMLUtil.childNodesLength(parent,Node.ELEMENT_NODE,caseSensitive,filter);
068            }
069    
070            @Override
071            public Node item(int index) {
072                    return XMLCaster.toXMLStruct(getChildNode(index),caseSensitive);
073            }
074    
075            @Override
076            public int size() {
077                    return getLength();
078            }
079    
080            @Override
081            public Collection.Key[] keys() {
082                    Collection.Key[] keys=new Collection.Key[getLength()];
083                    for(int i=1;i<=keys.length;i++) {
084                            keys[i-1]=KeyImpl.init(i+"");
085                    }
086                    return keys;
087            }
088            
089            @Override
090            public int[] intKeys() {
091                    int[] keys=new int[getLength()];
092                    for(int i=1;i<=keys.length;i++) {
093                            keys[i-1]=i;
094                    }
095                    return keys;
096            }
097            
098            public Object removeEL(Collection.Key key) {
099                    return removeEL(Caster.toIntValue(key.getString(),-1));
100            }
101    
102    
103            @Override
104            public Object remove(Collection.Key key) throws PageException {
105                    return removeE(Caster.toIntValue(key.getString()));
106            }
107    
108            @Override
109            public Object removeEL(int index) {
110                    int len=size();
111                    if(index<1 || index>len) return null;
112                    try {
113                            return XMLCaster.toXMLStruct(parent.removeChild(XMLCaster.toRawNode(item(index-1))),caseSensitive);
114                    } 
115                    catch (Exception e) {
116                            return null;
117                    }
118            }
119            
120            @Override
121            public Object removeE(int index) throws PageException {
122                    int len=size();
123                    if(index<1 || index>len)
124                            throw new ExpressionException("can't remove value form XML Node List at index "+index+
125                                    ", valid indexes goes from 1 to "+len);
126                    return XMLCaster.toXMLStruct(parent.removeChild(XMLCaster.toRawNode(item(index-1))),caseSensitive);
127            }
128    
129            @Override
130            public void clear() {
131                    Node[] nodes=getChildNodesAsArray();
132                    for(int i=0;i<nodes.length;i++) {
133                            parent.removeChild(XMLCaster.toRawNode(nodes[i]));
134                    }
135            }
136    
137    
138            @Override
139            public Object get(String key) throws ExpressionException {
140                    return getE(Caster.toIntValue(key));
141            }
142    
143            @Override
144            public Object get(Collection.Key key) throws ExpressionException {
145                    return get(key.getString());
146            }
147            
148            @Override
149            public Object getE(int key) throws ExpressionException {
150                    Object rtn= item(key-1);
151                    if(rtn==null) throw new ExpressionException("invalid index ["+key+"] for XML Node List , indexes goes from [0-"+size()+"]");
152                    return rtn;
153            }
154    
155            @Override
156            public Object get(String key, Object defaultValue) {
157                    int index=Caster.toIntValue(key,Integer.MIN_VALUE);
158                    if(index==Integer.MIN_VALUE) return defaultValue;
159                return get(index,defaultValue);
160            }
161    
162            @Override
163            public Object get(Collection.Key key, Object defaultValue) {
164                    return get(key.getString(),defaultValue);
165            }
166    
167            @Override
168            public Object get(int key, Object defaultValue) {
169                    Object rtn= item(key-1);
170                    if(rtn==null) return defaultValue;
171                    return rtn;
172            }
173    
174            @Override
175            public Object set(String key, Object value) throws PageException {
176                    return setE(Caster.toIntValue(key),value);
177            }
178    
179            @Override
180            public Object set(Collection.Key key, Object value) throws PageException {
181                    return set(key.getString(), value);
182            }
183            
184            @Override
185            public Object setE(int index, Object value) throws PageException {
186                    // check min Index
187                            if(index<1)
188                                    throw new ExpressionException("invalid index ["+index+"] to set a child node, valid indexes start at 1");
189                    
190                    Node[] nodes=getChildNodesAsArray();
191                    
192                    // if index Greater len append
193                            if(index>nodes.length) return append(value);
194                    
195                    // remove all children
196                    clear();
197                    
198                    // set all children before new Element
199                    for(int i=1;i<index;i++) {
200                            append(nodes[i-1]);
201                    }
202                    
203                    // set new Element
204                    append(XMLCaster.toNode(doc,value));
205                    
206                    // set all after new Element
207                    for(int i=index;i<nodes.length;i++) {
208                            append(nodes[i]);
209                    }
210                    
211                    return value;
212            }
213    
214            @Override
215            public Object setEL(String key, Object value) {
216                    int index=Caster.toIntValue(key,Integer.MIN_VALUE);
217                    if(index==Integer.MIN_VALUE) return null;
218                    return setEL(index,value);
219            }
220    
221            @Override
222            public Object setEL(Collection.Key key, Object value) {
223                    return setEL(key.getString(), value);
224            }
225            
226            @Override
227            public Object setEL(int index, Object value) {
228                    try {
229                            return setE(index,value);
230                    } catch (PageException e) {
231                            return null;
232                    }
233            }
234    
235            @Override
236            public Iterator<Collection.Key> keyIterator() {
237                    return new KeyIterator(keys());
238            }
239        
240        @Override
241            public Iterator<String> keysAsStringIterator() {
242            return new StringIterator(keys());
243        }
244            
245            @Override
246            public Iterator<Entry<Key, Object>> entryIterator() {
247                    return new EntryIterator(this,keys());
248            }
249            
250            public Iterator<Object> valueIterator() {
251                    Object[] values=new Object[getLength()];
252                    for(int i=0;i<values.length;i++) {
253                            values[i]=item(i);
254                    }
255                    return new ArrayIterator(values);
256            }
257    
258            @Override
259            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
260                    maxlevel--;
261                    DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
262                    table.setTitle("Array (XML Node List)");
263                    int len=size();
264                    
265                    for(int i=1;i<=len;i++) {
266                            table.appendRow(1,new SimpleDumpData(i),DumpUtil.toDumpData(item(i-1), pageContext,maxlevel,dp));
267                    }
268                    return table;
269            }
270            
271            @Override
272            public Object append(Object o) throws PageException {
273                    return parent.appendChild(XMLCaster.toNode(doc,o));
274            }
275            
276            public Object appendEL(Object o) {
277                    try {
278                            return append(o);
279                    } catch (Exception e) {
280                            return null;
281                    }
282            }
283            
284            @Override
285            public Object clone() {
286                    return duplicate(true);
287            }
288    
289    
290            @Override
291            public Collection duplicate(boolean deepCopy) {
292                    return new XMLNodeList(parent.cloneNode(deepCopy),caseSensitive);
293            }
294            
295    
296            @Override
297            public int getDimension() {
298                    return 1;
299            }
300            
301            @Override
302            public boolean insert(int index, Object value) throws PageException {
303                    // check min Index
304                    if(index<1)
305                            throw new ExpressionException("invalid index ["+index+"] to insert a child node, valid indexes start at 1");
306            
307                    Node[] nodes=getChildNodesAsArray();
308                    
309                    // if index Greater len append
310                            if(index>nodes.length) {
311                                    append(value);
312                                    return true;
313                            }
314                    
315                    // remove all children
316                    clear();
317                    
318                    // set all children before new Element
319                    for(int i=1;i<index;i++) {
320                            append(nodes[i-1]);
321                    }
322                    
323                    // set new Element
324                    append(XMLCaster.toNode(doc,value));
325                    
326                    // set all after new Element
327                    for(int i=index;i<=nodes.length;i++) {
328                            append(nodes[i-1]);
329                    }
330                    
331                    return true;
332            }
333            
334            @Override
335            public Object prepend(Object o) throws PageException {
336                    
337                    Node[] nodes=getChildNodesAsArray();
338                    
339                    // remove all children
340                    clear();
341                    
342                    // set new Element
343                    append(XMLCaster.toNode(doc,o));
344                    
345                    // set all after new Element
346                    for(int i=0;i<nodes.length;i++) {
347                            append(nodes[i]);
348                    }
349                    return o;
350            }
351            
352            @Override
353            public void resize(int to) throws ExpressionException {
354                    if(to>size())throw new ExpressionException("can't resize a XML Node List Array with empty Elements");
355            }
356            
357            @Override
358            public void sort(String sortType, String sortOrder)
359                            throws ExpressionException {
360                    throw new ExpressionException("can't sort a XML Node List Array","sorttype:"+sortType+";sortorder:"+sortOrder);
361            }
362            
363            @Override
364            public void sort(Comparator comp)
365                            throws ExpressionException {
366                    throw new ExpressionException("can't sort a XML Node List Array");
367            }
368    
369            @Override
370            public Object[] toArray() {
371                    return getChildNodesAsArray();
372            }
373            
374            public ArrayList toArrayList() {
375                    Object[] arr=toArray();
376                    ArrayList list=new ArrayList();
377                    for(int i=0;i>arr.length;i++) {
378                            list.add(arr[i]);
379                    }
380                    return list;
381            }
382            
383            /**
384             * @return returns a output from the content as plain Text
385             */
386            public String toPlain() {
387                    StringBuffer sb=new StringBuffer();
388                    int length=size();
389                    for(int i=1;i<=length;i++) {
390                            sb.append(i);
391                            sb.append(": ");
392                            sb.append(get(i,null));
393                            sb.append("\n");
394                    }
395                    return sb.toString();
396            }
397    
398        private NodeList getChildNodes() {
399                    return XMLUtil.getChildNodes(parent,Node.ELEMENT_NODE,caseSensitive,filter);
400            }
401        
402        private Node getChildNode(int index) {
403                    return XMLUtil.getChildNode(parent,Node.ELEMENT_NODE,caseSensitive,filter,index);
404            }
405            
406            private Node[] getChildNodesAsArray() {
407                    return XMLUtil.getChildNodesAsArray(parent,Node.ELEMENT_NODE,caseSensitive,filter);
408            }
409    
410        @Override
411        public boolean containsKey(String key) {
412            return get(key,null)!=null;
413        }   
414    
415            @Override
416            public boolean containsKey(Collection.Key key) {
417            return get(key,null)!=null;
418            }
419    
420        @Override
421        public boolean containsKey(int key) {
422            return get(key,null)!=null;
423        }
424    
425        @Override
426        public boolean getCaseSensitive() {
427            return caseSensitive;
428        }      
429        
430        @Override
431        public String castToString() throws ExpressionException {
432            throw new ExpressionException("Can't cast XML NodeList to String");
433        }
434        
435            @Override
436            public String castToString(String defaultValue) {
437                    return defaultValue;
438            }
439    
440        @Override
441        public boolean castToBooleanValue() throws ExpressionException {
442            throw new ExpressionException("Can't cast XML NodeList to a boolean value");
443        }
444        
445        @Override
446        public Boolean castToBoolean(Boolean defaultValue) {
447            return defaultValue;
448        }
449    
450    
451        @Override
452        public double castToDoubleValue() throws ExpressionException {
453            throw new ExpressionException("Can't cast XML NodeList to a number value");
454        }
455        
456        @Override
457        public double castToDoubleValue(double defaultValue) {
458            return defaultValue;
459        }
460    
461    
462        @Override
463        public DateTime castToDateTime() throws ExpressionException {
464            throw new ExpressionException("Can't cast XML NodeList to a Date");
465        }
466        
467        @Override
468        public DateTime castToDateTime(DateTime defaultValue) {
469            return defaultValue;
470        }
471    
472            @Override
473            public int compareTo(boolean b) throws ExpressionException {
474                    throw new ExpressionException("can't compare XML NodeList with a boolean value");
475            }
476    
477            @Override
478            public int compareTo(DateTime dt) throws PageException {
479                    throw new ExpressionException("can't compare XML NodeList with a DateTime Object");
480            }
481    
482            @Override
483            public int compareTo(double d) throws PageException {
484                    throw new ExpressionException("can't compare XML NodeList with a numeric value");
485            }
486    
487            @Override
488            public int compareTo(String str) throws PageException {
489                    throw new ExpressionException("can't compare XML NodeList with a String");
490            }
491    
492            @Override
493            public long sizeOf() {
494                    return ArrayUtil.sizeOf((List)this);
495            }
496    }