001    package railo.runtime.text.xml.struct;
002    
003    import java.lang.reflect.Method;
004    import java.util.Date;
005    import java.util.Iterator;
006    import java.util.Map;
007    
008    import org.w3c.dom.DOMException;
009    import org.w3c.dom.Document;
010    import org.w3c.dom.Element;
011    import org.w3c.dom.NamedNodeMap;
012    import org.w3c.dom.Node;
013    import org.w3c.dom.NodeList;
014    import org.w3c.dom.UserDataHandler;
015    import org.xml.sax.SAXException;
016    
017    import railo.commons.collections.HashTable;
018    import railo.runtime.PageContext;
019    import railo.runtime.dump.DumpData;
020    import railo.runtime.dump.DumpProperties;
021    import railo.runtime.dump.DumpUtil;
022    import railo.runtime.exp.ExpressionException;
023    import railo.runtime.exp.PageException;
024    import railo.runtime.exp.PageRuntimeException;
025    import railo.runtime.exp.XMLException;
026    import railo.runtime.op.Caster;
027    import railo.runtime.op.Operator;
028    import railo.runtime.text.xml.XMLAttributes;
029    import railo.runtime.text.xml.XMLCaster;
030    import railo.runtime.text.xml.XMLNodeList;
031    import railo.runtime.text.xml.XMLUtil;
032    import railo.runtime.type.Collection;
033    import railo.runtime.type.KeyImpl;
034    import railo.runtime.type.dt.DateTime;
035    import railo.runtime.type.it.EntryIterator;
036    import railo.runtime.type.it.KeyIterator;
037    import railo.runtime.type.it.StringIterator;
038    import railo.runtime.type.it.ValueIterator;
039    import railo.runtime.type.util.ArrayUtil;
040    import railo.runtime.type.util.StructSupport;
041    
042    /**
043     * 
044     */
045    public class XMLNodeStruct extends StructSupport implements XMLStruct {
046            
047            private Node node;
048            protected boolean caseSensitive;
049        
050            /**
051             * constructor of the class 
052             * @param node Node 
053             * @param caseSensitive
054             */
055            protected XMLNodeStruct(Node node, boolean caseSensitive) {
056                    if(node instanceof XMLStruct)node=((XMLStruct)node).toNode();
057                    this.node=node;
058                    this.caseSensitive=caseSensitive;
059            }
060            
061            @Override
062            public Object remove(Key key) throws PageException {
063            Object o= XMLUtil.removeProperty(node,key,caseSensitive);
064            if(o!=null)return o;           
065            throw new ExpressionException("node has no child with name ["+key+"]");
066            }
067    
068            @Override
069            public Object removeEL(Key key) {
070            return  XMLUtil.removeProperty(node,key,caseSensitive);
071            }
072            
073            @Override
074            public Object get(Collection.Key key) throws PageException {
075                    try {               
076                            return XMLUtil.getProperty(node,key,caseSensitive);
077                    } catch (SAXException e) {
078                            throw new XMLException(e);
079                    }
080            }
081            
082            @Override
083            public Object set(Collection.Key key, Object value) throws PageException {
084                    return XMLUtil.setProperty(node,key,value,caseSensitive);
085            }
086            
087            /**
088             * @return retun the inner map
089             */
090            public Map getMap() {
091                    NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hier ok?
092                    Map map=new HashTable();
093                    int len=elements.getLength();
094                    
095                    for(int i=0;i<len;i++) {
096                            Node node=elements.item(i);
097                            map.put(node.getNodeName(),node);
098                    }
099                    return map;
100            }
101            
102            @Override
103            public Collection duplicate(boolean deepCopy) {
104                    return new XMLNodeStruct(node.cloneNode(deepCopy),caseSensitive);
105            }
106    
107    
108            
109            
110            
111    
112            @Override
113            public Node cloneNode(boolean deep) {
114                    return new XMLNodeStruct(node.cloneNode(deep),caseSensitive);
115            }
116            
117            
118            @Override
119            public short getNodeType() {
120                    return node.getNodeType();
121            }
122            
123            @Override
124            public void normalize() {
125                    node.normalize();
126            }
127            
128            @Override
129            public boolean hasAttributes() {
130                    return node.hasAttributes();
131            }
132            
133            @Override
134            public boolean hasChildNodes() {
135                    return node.hasChildNodes();
136            }
137            
138            @Override
139            public String getLocalName() {
140                    return node.getLocalName();
141            }
142            
143            @Override
144            public String getNamespaceURI() {
145                    return node.getNamespaceURI();
146            }
147            
148            @Override
149            public String getNodeName() {
150                    return node.getNodeName();
151            }
152            
153            @Override
154            public String getNodeValue() throws DOMException {
155                    return node.getNodeValue();
156            }
157            
158            @Override
159            public String getPrefix() {
160                    return node.getPrefix();
161            }
162            
163            @Override
164            public void setNodeValue(String nodeValue) throws DOMException {
165                    node.setNodeValue(nodeValue);
166            }
167            
168            @Override
169            public void setPrefix(String prefix) throws DOMException {
170                    node.setPrefix(prefix);
171            }
172            
173            @Override
174            public Document getOwnerDocument() {
175                    if(node instanceof Document) return (Document) node;
176                    return node.getOwnerDocument();
177            }
178            
179            @Override
180            public NamedNodeMap getAttributes() {
181                    return new XMLAttributes(node,caseSensitive);
182            }
183            
184            @Override
185            public Node getFirstChild() {
186                    return node.getFirstChild();
187            }
188            
189            @Override
190            public Node getLastChild() {
191                    return node.getLastChild();
192            }
193            
194            @Override
195            public Node getNextSibling() {
196                    return node.getNextSibling();
197            }
198            
199            @Override
200            public Node getParentNode() {
201                    return node.getParentNode();
202            }
203            
204            @Override
205            public Node getPreviousSibling() {
206                    return node.getPreviousSibling();
207            }
208            
209            
210            
211            @Override
212            public NodeList getChildNodes() {
213                    return node.getChildNodes();
214            }
215            
216            @Override
217            public boolean isSupported(String feature, String version) {
218                    return node.isSupported(feature, version);
219            }
220            
221            @Override
222            public Node appendChild(Node newChild) throws DOMException {
223                    return node.appendChild(newChild);
224            }
225            
226            @Override
227            public Node removeChild(Node oldChild) throws DOMException {
228                    return node.removeChild(XMLCaster.toRawNode(oldChild));
229            }
230            
231            @Override
232            public Node insertBefore(Node newChild, Node refChild) throws DOMException {
233                    return node.insertBefore(newChild, refChild);
234            }
235            
236            @Override
237            public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
238                    return node.replaceChild(XMLCaster.toRawNode(newChild), XMLCaster.toRawNode(oldChild));
239            }
240            
241            @Override
242            public int size() {
243                    NodeList list = node.getChildNodes();
244                    int len=list.getLength();
245                    int count=0;
246                    for(int i=0;i<len;i++) {
247                            if(list.item(i) instanceof Element) count++;
248                    }
249                    return count;
250            }
251    
252            public Collection.Key[] keys() {
253                    NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hie ok
254                    Collection.Key[] arr=new Collection.Key[elements.getLength()];
255                    for(int i=0;i<arr.length;i++) {
256                            arr[i]=KeyImpl.init(elements.item(i).getNodeName());
257                    }
258                    return arr;
259            }
260            
261            @Override
262            public void clear() {
263                    /*NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE);
264                    int len=elements.getLength();
265                    for(int i=0;i<len;i++) {
266                            node.removeChild(elements.item(i));
267                    }*/
268            }
269            
270            @Override
271            public Object get(Collection.Key key, Object defaultValue) {
272                    return XMLUtil.getProperty(node,key,caseSensitive,defaultValue);
273            }
274    
275            @Override
276            public Object setEL(Key key, Object value) {
277                    return XMLUtil.setProperty(node,key,value,caseSensitive,null);
278            }
279            
280            @Override
281            public Iterator<Collection.Key> keyIterator() {
282                    return new KeyIterator(keys());
283            }
284        
285        @Override
286            public Iterator<String> keysAsStringIterator() {
287            return new StringIterator(keys());
288        }
289            
290            @Override
291            public Iterator<Entry<Key, Object>> entryIterator() {
292                    return new EntryIterator(this,keys());
293            }
294            
295            @Override
296            public Iterator<Object> valueIterator() {
297                    return new ValueIterator(this,keys());
298            }
299    
300            @Override
301            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
302                    return DumpUtil.toDumpData(node, pageContext,maxlevel,dp);
303            }
304    
305            @Override
306            public final Node toNode() {
307                    return node;
308            }
309            
310            /**
311             * @return Returns the caseSensitive.
312             */
313            public boolean getCaseSensitive() {
314                    return caseSensitive;
315            }
316            
317            @Override
318            public boolean containsKey(Collection.Key key) {
319            return get(key,null)!=null;
320            }
321    
322        @Override
323        public XMLNodeList getXMLNodeList() {
324            return new XMLNodeList(node,getCaseSensitive());
325        }   
326    
327        @Override
328        public String castToString() throws PageException {
329            return XMLCaster.toString(this.node);
330        }
331        
332        @Override
333        public String castToString(String defaultValue) {
334            return XMLCaster.toString(this.node,defaultValue);
335        }
336    
337        @Override
338        public boolean castToBooleanValue() throws ExpressionException {
339            throw new ExpressionException("Can't cast XML Node to a boolean value");
340        }
341        
342        @Override
343        public Boolean castToBoolean(Boolean defaultValue) {
344            return defaultValue;
345        }
346    
347    
348        @Override
349        public double castToDoubleValue() throws ExpressionException {
350            throw new ExpressionException("Can't cast XML Node to a number value");
351        }
352        
353        @Override
354        public double castToDoubleValue(double defaultValue) {
355            return defaultValue;
356        }
357    
358    
359        @Override
360        public DateTime castToDateTime() throws ExpressionException {
361            throw new ExpressionException("Can't cast XML Node to a Date");
362        }
363        
364        @Override
365        public DateTime castToDateTime(DateTime defaultValue) {
366            return defaultValue;
367        }
368    
369            @Override
370            public int compareTo(boolean b) throws PageException {
371                    return Operator.compare(castToString(), b);
372            }
373    
374            @Override
375            public int compareTo(DateTime dt) throws PageException {
376                    return Operator.compare(castToString(), (Date)dt);
377            }
378    
379            @Override
380            public int compareTo(double d) throws PageException {
381                    return Operator.compare(castToString(), d);
382            }
383    
384            @Override
385            public int compareTo(String str) throws PageException {
386                    return Operator.compare(castToString(), str);
387            }
388    
389        public String getBaseURI() {
390            // not supported
391            return null;
392        }
393    
394        public short compareDocumentPosition(Node other) throws DOMException {
395            // not supported
396            return -1;
397        }
398    
399        public void setTextContent(String textContent) throws DOMException {
400            //TODO  not supported
401            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,"this method is not supported");
402        }
403    
404        public boolean isSameNode(Node other) {
405            return this==other;
406        }
407    
408        public String lookupPrefix(String namespaceURI) {
409    //      TODO not supported
410            return null;
411        }
412    
413        public boolean isDefaultNamespace(String namespaceURI) {
414    //      TODO not supported
415            return false;
416        }
417    
418        public String lookupNamespaceURI(String prefix) {
419    //      TODO not supported
420            return null;
421        }
422    
423        public boolean isEqualNode(Node node) {
424    //      TODO not supported
425            return this==node;
426        }
427    
428        public Object getFeature(String feature, String version) {
429            // TODO not supported
430            return null;
431        }
432    
433        public Object getUserData(String key) {
434            // dynamic load to support jre 1.4 and 1.5
435                    try {
436                            Method m = node.getClass().getMethod("getUserData", new Class[]{key.getClass()});
437                            return m.invoke(node, new Object[]{key});
438                    } 
439                    catch (Exception e) {
440                            throw new PageRuntimeException(Caster.toPageException(e));
441                    }
442        }
443    
444            public String getTextContent() throws DOMException {
445            // dynamic load to support jre 1.4 and 1.5
446                    try {
447                            Method m = node.getClass().getMethod("getTextContent", new Class[]{});
448                            return Caster.toString(m.invoke(node, ArrayUtil.OBJECT_EMPTY));
449                    } 
450                    catch (Exception e) {
451                            throw new PageRuntimeException(Caster.toPageException(e));
452                    }
453            }
454    
455            public Object setUserData(String key, Object data, UserDataHandler handler) {
456            // dynamic load to support jre 1.4 and 1.5
457                    try {
458                            Method m = node.getClass().getMethod("setUserData", new Class[]{key.getClass(),data.getClass(),handler.getClass()});
459                            return m.invoke(node, new Object[]{key,data,handler});
460                    } 
461                    catch (Exception e) {
462                            throw new PageRuntimeException(Caster.toPageException(e));
463                    }
464            }
465    
466            public boolean isCaseSensitive() {
467                    return caseSensitive;
468            }
469            
470            public boolean equals(Object obj) {
471                    if(!(obj instanceof XMLNodeStruct)) 
472                            return super.equals(obj);
473                    XMLNodeStruct other = ((XMLNodeStruct)obj);
474                    return other.caseSensitive=caseSensitive && other.node.equals(node);
475            }
476            
477            
478    
479    }