001    package railo.runtime.text.xml;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    
006    import org.w3c.dom.Attr;
007    import org.w3c.dom.DOMException;
008    import org.w3c.dom.Document;
009    import org.w3c.dom.NamedNodeMap;
010    import org.w3c.dom.Node;
011    
012    import railo.runtime.PageContext;
013    import railo.runtime.dump.DumpData;
014    import railo.runtime.dump.DumpProperties;
015    import railo.runtime.dump.DumpTable;
016    import railo.runtime.dump.DumpUtil;
017    import railo.runtime.dump.SimpleDumpData;
018    import railo.runtime.exp.ExpressionException;
019    import railo.runtime.exp.PageException;
020    import railo.runtime.exp.XMLException;
021    import railo.runtime.op.Caster;
022    import railo.runtime.type.Collection;
023    import railo.runtime.type.KeyImpl;
024    import railo.runtime.type.Struct;
025    import railo.runtime.type.dt.DateTime;
026    import railo.runtime.type.it.EntryIterator;
027    import railo.runtime.type.it.KeyIterator;
028    import railo.runtime.type.it.StringIterator;
029    import railo.runtime.type.it.ValueIterator;
030    import railo.runtime.type.util.ListUtil;
031    import railo.runtime.type.util.StructSupport;
032    
033    /**
034     * represent a Struct and a NamedNodeMap
035     */
036    public final class XMLAttributes extends StructSupport implements Struct,NamedNodeMap {
037            
038    
039            private final NamedNodeMap nodeMap;
040            private final Document owner;
041            private final Node parent;
042            private final boolean caseSensitive;
043    
044            /**
045             * constructor of the class (readonly)
046             * @param nodeMap
047             */
048            public XMLAttributes(Node parent, boolean caseSensitive) {
049                    this.owner=parent.getOwnerDocument();
050                    this.parent=parent;
051                    this.nodeMap=parent.getAttributes();
052                    this.caseSensitive=caseSensitive;
053            }
054    
055            @Override
056            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
057                    Collection.Key[] keys=keys();
058                    maxlevel--;
059                    DumpTable table = new DumpTable("xml","#999966","#cccc99","#000000");
060                    table.setTitle("Struct (XML Attributes)");
061    
062                    int maxkeys=dp.getMaxKeys();
063                    int index=0;
064                    Collection.Key k;
065                    for(int i=0;i<keys.length;i++) {
066                            k=keys[i];
067                            
068                            if(DumpUtil.keyValid(dp,maxlevel, k)){
069                                    if(maxkeys<=index++)break;
070                                    table.appendRow(1,new SimpleDumpData(k.getString()),DumpUtil.toDumpData(get(k.getString(),null), pageContext,maxlevel,dp));
071                            }
072                    }
073                    return table;
074            }
075            
076    
077            @Override
078            public int size() {
079                    return nodeMap.getLength();
080            }
081            
082            @Override
083            public Collection.Key[] keys() {
084                    int len=nodeMap.getLength();
085                    ArrayList<Collection.Key> list =new ArrayList<Collection.Key>();
086                    for(int i=0;i<len;i++) {
087                            Node item = nodeMap.item(i);
088                            if(item instanceof Attr)
089                                    list.add(KeyImpl.init(((Attr)item).getName()));
090                    }
091                    return list.toArray(new Collection.Key[list.size()]);
092            }
093        
094            @Override
095            public Object remove(Collection.Key k) throws PageException {
096                    String key=k.getString();
097                    Node rtn=null;
098                    if(!caseSensitive){
099                            int len = nodeMap.getLength();
100                            String nn;
101                            for(int i=len-1;i>=0;i--) {
102                                    nn=nodeMap.item(i).getNodeName();
103                                    if(key.equalsIgnoreCase(nn)) rtn=nodeMap.removeNamedItem(nn);
104                            }
105                    }
106                    else rtn=nodeMap.removeNamedItem(toName(key));
107                    
108                    if(rtn!=null) return rtn.getNodeValue();
109                    throw new ExpressionException("can't remove element with name ["+key+"], element doesn't exist");
110            }       
111        
112        @Override
113        public Object removeEL(Collection.Key k) {
114            String key=k.getString();
115                    Node rtn=null;
116                    if(!caseSensitive){
117                            int len = nodeMap.getLength();
118                            String nn;
119                            for(int i=len-1;i>=0;i--) {
120                                    nn=nodeMap.item(i).getNodeName();
121                                    if(key.equalsIgnoreCase(nn)) rtn=nodeMap.removeNamedItem(nn);
122                            }
123                    }
124                    else rtn=nodeMap.removeNamedItem(toName(key));
125                    
126                    if(rtn!=null) return rtn.getNodeValue();
127                    return null;
128        }
129        
130            @Override
131            public void clear() {
132                    Collection.Key[] keys=keys();
133                    for(int i=0;i<keys.length;i++) {
134                            nodeMap.removeNamedItem(keys[i].getString());
135                    }
136            }
137    
138            @Override
139            public Object get(Collection.Key key) throws ExpressionException {
140                    Node rtn = nodeMap.getNamedItem(key.getString());
141                    if(rtn!=null) return rtn.getNodeValue();
142                    
143                    Collection.Key[] keys=keys();
144                    for(int i=0;i<keys.length;i++) {
145                            if(key.equalsIgnoreCase(keys[i]))
146                                    return nodeMap.getNamedItem(keys[i].getString()).getNodeValue();
147                    }
148                    throw new ExpressionException("No Attribute "+key.getString()+" defined for tag","attributes are ["+ListUtil.arrayToList(keys,", ")+"]");
149            }
150    
151            @Override
152            public Object get(Collection.Key key, Object defaultValue) {
153                    try {
154                            return get(key);
155                    } catch (PageException e) {
156                            return defaultValue;
157                    }
158            }
159    
160            @Override
161            public Object set(Collection.Key key, Object value) throws PageException {
162                    if(owner==null) return value;
163                    
164                    try {
165                            Attr attr=owner.createAttribute(toName(key.getString()));
166                            attr.setValue(Caster.toString(value));
167                            nodeMap.setNamedItem(attr);
168                            
169                    }
170                    catch(DOMException de) {
171                            throw new XMLException(de);
172                    }
173                    
174                    
175                    
176                    
177                    return value;
178            }
179    
180            private String toName(String name) {
181                    return toName(name,name);
182            }
183            private String toName(String name, String defaultValue) {
184                    if(caseSensitive) return name;
185                    
186                    Node n = nodeMap.getNamedItem(name);
187                    if(n!=null) return n.getNodeName();
188                    
189                    int len = nodeMap.getLength();
190                    String nn;
191                    for(int i=0;i<len;i++) {
192                            nn=nodeMap.item(i).getNodeName();
193                            if(name.equalsIgnoreCase(nn)) return nn;
194                    }
195                    return defaultValue;
196            }
197            
198            @Override
199            public Object setEL(Collection.Key key, Object value) {
200                    if(owner==null) return value;
201                    try {
202                            Attr attr=owner.createAttribute(toName(key.getString()));
203                            attr.setValue(Caster.toString(value));
204                            nodeMap.setNamedItem(attr);
205                    }
206                    catch(Exception e) {
207                            return null;
208                    }
209                    return value;
210            }
211            
212            @Override
213            public Iterator<Collection.Key> keyIterator() {
214                    return new KeyIterator(keys());
215            }
216        
217        @Override
218            public Iterator<String> keysAsStringIterator() {
219            return new StringIterator(keys());
220        }
221            
222            @Override
223            public Iterator<Entry<Key, Object>> entryIterator() {
224                    return new EntryIterator(this,keys());
225            }
226            
227            @Override
228            public Iterator<Object> valueIterator() {
229                    return new ValueIterator(this,keys());
230            }
231    
232            @Override
233            public int getLength() {
234                    return nodeMap.getLength();
235            }
236    
237            @Override
238            public Node item(int index) {
239                    return nodeMap.item(index);
240            }
241    
242            @Override
243            public Node getNamedItem(String name) {
244                    return nodeMap.getNamedItem(name);
245            }
246    
247            @Override
248            public Node removeNamedItem(String name) throws DOMException {
249                    return nodeMap.removeNamedItem(name);
250            }
251    
252            @Override
253            public Node setNamedItem(Node arg) throws DOMException {
254                    return nodeMap.setNamedItem(arg);
255            }
256    
257            @Override
258            public Node setNamedItemNS(Node arg) throws DOMException {
259                    return nodeMap.setNamedItemNS(arg);
260            }
261    
262            @Override
263            public Node getNamedItemNS(String namespaceURI, String localName) {
264                    return nodeMap.getNamedItemNS(namespaceURI,localName);
265            }
266    
267            @Override
268            public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException {
269                    return nodeMap.removeNamedItemNS(namespaceURI, localName);
270            }
271    
272            @Override
273            public Collection duplicate(boolean deepCopy) {
274                    return new XMLAttributes(parent.cloneNode(deepCopy),caseSensitive);
275            }
276            
277            
278            /**
279             * @return returns named Node map
280             */
281            public NamedNodeMap toNamedNodeMap() {
282                    return nodeMap;
283            }
284    
285            @Override
286            public boolean containsKey(Collection.Key key) {
287            return get(key,null)!=null;
288            }
289        
290        @Override
291        public String castToString() throws ExpressionException {
292            throw new ExpressionException("Can't cast XML NamedNodeMap to String");
293        }
294        
295            @Override
296            public String castToString(String defaultValue) {
297                    return defaultValue;
298            }
299    
300        @Override
301        public boolean castToBooleanValue() throws ExpressionException {
302            throw new ExpressionException("Can't cast XML NamedNodeMap to a boolean value");
303        }
304        
305        @Override
306        public Boolean castToBoolean(Boolean defaultValue) {
307            return defaultValue;
308        }
309    
310    
311        @Override
312        public double castToDoubleValue() throws ExpressionException {
313            throw new ExpressionException("Can't cast XML NamedNodeMap to a number value");
314        }
315        
316        @Override
317        public double castToDoubleValue(double defaultValue) {
318            return defaultValue;
319        }
320    
321    
322        @Override
323        public DateTime castToDateTime() throws ExpressionException {
324            throw new ExpressionException("Can't cast XML NamedNodeMap to a date value");
325        }
326        
327        @Override
328        public DateTime castToDateTime(DateTime defaultValue) {
329            return defaultValue;
330        }
331    
332            @Override
333            public int compareTo(boolean b) throws ExpressionException {
334                    throw new ExpressionException("can't compare XML NamedNodeMap with a boolean value");
335            }
336    
337            @Override
338            public int compareTo(DateTime dt) throws PageException {
339                    throw new ExpressionException("can't compare XML NamedNodeMap with a DateTime Object");
340            }
341    
342            @Override
343            public int compareTo(double d) throws PageException {
344                    throw new ExpressionException("can't compare XML NamedNodeMap with a numeric value");
345            }
346    
347            @Override
348            public int compareTo(String str) throws PageException {
349                    throw new ExpressionException("can't compare XML NamedNodeMap with a String");
350            }
351    }