package railo.runtime.text.xml.struct;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.UserDataHandler;
import org.xml.sax.SAXException;
import railo.commons.collection.MapFactory;
import railo.runtime.PageContext;
import railo.runtime.dump.DumpData;
import railo.runtime.dump.DumpProperties;
import railo.runtime.dump.DumpUtil;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.exp.PageRuntimeException;
import railo.runtime.exp.XMLException;
import railo.runtime.op.Caster;
import railo.runtime.op.Operator;
import railo.runtime.text.xml.XMLAttributes;
import railo.runtime.text.xml.XMLCaster;
import railo.runtime.text.xml.XMLNodeList;
import railo.runtime.text.xml.XMLUtil;
import railo.runtime.type.Collection;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.it.EntryIterator;
import railo.runtime.type.it.KeyIterator;
import railo.runtime.type.it.StringIterator;
import railo.runtime.type.it.ValueIterator;
import railo.runtime.type.util.ArrayUtil;
import railo.runtime.type.util.StructSupport;
/**
*
*/
public class XMLNodeStruct extends StructSupport implements XMLStruct {
private Node node;
protected boolean caseSensitive;
/**
* constructor of the class
* @param node Node
* @param caseSensitive
*/
protected XMLNodeStruct(Node node, boolean caseSensitive) {
if(node instanceof XMLStruct)node=((XMLStruct)node).toNode();
this.node=node;
this.caseSensitive=caseSensitive;
}
@Override
public Object remove(Key key) throws PageException {
Object o= XMLUtil.removeProperty(node,key,caseSensitive);
if(o!=null)return o;
throw new ExpressionException("node has no child with name ["+key+"]");
}
@Override
public Object removeEL(Key key) {
return XMLUtil.removeProperty(node,key,caseSensitive);
}
@Override
public Object get(Collection.Key key) throws PageException {
try {
return XMLUtil.getProperty(node,key,caseSensitive);
} catch (SAXException e) {
throw new XMLException(e);
}
}
@Override
public Object set(Collection.Key key, Object value) throws PageException {
return XMLUtil.setProperty(node,key,value,caseSensitive);
}
/**
* @return retun the inner map
*/
public Map<String,Node> getMap() {
NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hier ok?
Map<String,Node> map=MapFactory.<String,Node>getConcurrentMap();
int len=elements.getLength();
for(int i=0;i<len;i++) {
Node node=elements.item(i);
map.put(node.getNodeName(),node);
}
return map;
}
@Override
public Collection duplicate(boolean deepCopy) {
return new XMLNodeStruct(node.cloneNode(deepCopy),caseSensitive);
}
@Override
public Node cloneNode(boolean deep) {
return new XMLNodeStruct(node.cloneNode(deep),caseSensitive);
}
@Override
public short getNodeType() {
return node.getNodeType();
}
@Override
public void normalize() {
node.normalize();
}
@Override
public boolean hasAttributes() {
return node.hasAttributes();
}
@Override
public boolean hasChildNodes() {
return node.hasChildNodes();
}
@Override
public String getLocalName() {
return node.getLocalName();
}
@Override
public String getNamespaceURI() {
return node.getNamespaceURI();
}
@Override
public String getNodeName() {
return node.getNodeName();
}
@Override
public String getNodeValue() throws DOMException {
return node.getNodeValue();
}
@Override
public String getPrefix() {
return node.getPrefix();
}
@Override
public void setNodeValue(String nodeValue) throws DOMException {
node.setNodeValue(nodeValue);
}
@Override
public void setPrefix(String prefix) throws DOMException {
node.setPrefix(prefix);
}
@Override
public Document getOwnerDocument() {
if(node instanceof Document) return (Document) node;
return node.getOwnerDocument();
}
@Override
public NamedNodeMap getAttributes() {
return new XMLAttributes(node,caseSensitive);
}
@Override
public Node getFirstChild() {
return node.getFirstChild();
}
@Override
public Node getLastChild() {
return node.getLastChild();
}
@Override
public Node getNextSibling() {
return node.getNextSibling();
}
@Override
public Node getParentNode() {
return node.getParentNode();
}
@Override
public Node getPreviousSibling() {
return node.getPreviousSibling();
}
@Override
public NodeList getChildNodes() {
return node.getChildNodes();
}
@Override
public boolean isSupported(String feature, String version) {
return node.isSupported(feature, version);
}
@Override
public Node appendChild(Node newChild) throws DOMException {
return node.appendChild(newChild);
}
@Override
public Node removeChild(Node oldChild) throws DOMException {
return node.removeChild(XMLCaster.toRawNode(oldChild));
}
@Override
public Node insertBefore(Node newChild, Node refChild) throws DOMException {
return node.insertBefore(newChild, refChild);
}
@Override
public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
return node.replaceChild(XMLCaster.toRawNode(newChild), XMLCaster.toRawNode(oldChild));
}
@Override
public int size() {
NodeList list = node.getChildNodes();
int len=list.getLength();
int count=0;
for(int i=0;i<len;i++) {
if(list.item(i) instanceof Element) count++;
}
return count;
}
public Collection.Key[] keys() {
NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hie ok
Collection.Key[] arr=new Collection.Key[elements.getLength()];
for(int i=0;i<arr.length;i++) {
arr[i]=KeyImpl.init(elements.item(i).getNodeName());
}
return arr;
}
@Override
public void clear() {
/*NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE);
int len=elements.getLength();
for(int i=0;i<len;i++) {
node.removeChild(elements.item(i));
}*/
}
@Override
public Object get(Collection.Key key, Object defaultValue) {
return XMLUtil.getProperty(node,key,caseSensitive,defaultValue);
}
@Override
public Object setEL(Key key, Object value) {
return XMLUtil.setProperty(node,key,value,caseSensitive,null);
}
@Override
public Iterator<Collection.Key> keyIterator() {
return new KeyIterator(keys());
}
@Override
public Iterator<String> keysAsStringIterator() {
return new StringIterator(keys());
}
@Override
public Iterator<Entry<Key, Object>> entryIterator() {
return new EntryIterator(this,keys());
}
@Override
public Iterator<Object> valueIterator() {
return new ValueIterator(this,keys());
}
@Override
public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
return DumpUtil.toDumpData(node, pageContext,maxlevel,dp);
}
@Override
public final Node toNode() {
return node;
}
/**
* @return Returns the caseSensitive.
*/
public boolean getCaseSensitive() {
return caseSensitive;
}
@Override
public boolean containsKey(Collection.Key key) {
return get(key,null)!=null;
}
@Override
public XMLNodeList getXMLNodeList() {
return new XMLNodeList(node,getCaseSensitive());
}
@Override
public String castToString() throws PageException {
return XMLCaster.toString(this.node);
}
@Override
public String castToString(String defaultValue) {
return XMLCaster.toString(this.node,defaultValue);
}
@Override
public boolean castToBooleanValue() throws ExpressionException {
throw new ExpressionException("Can't cast XML Node to a boolean value");
}
@Override
public Boolean castToBoolean(Boolean defaultValue) {
return defaultValue;
}
@Override
public double castToDoubleValue() throws ExpressionException {
throw new ExpressionException("Can't cast XML Node to a number value");
}
@Override
public double castToDoubleValue(double defaultValue) {
return defaultValue;
}
@Override
public DateTime castToDateTime() throws ExpressionException {
throw new ExpressionException("Can't cast XML Node to a Date");
}
@Override
public DateTime castToDateTime(DateTime defaultValue) {
return defaultValue;
}
@Override
public int compareTo(boolean b) throws PageException {
return Operator.compare(castToString(), b);
}
@Override
public int compareTo(DateTime dt) throws PageException {
return Operator.compare(castToString(), (Date)dt);
}
@Override
public int compareTo(double d) throws PageException {
return Operator.compare(castToString(), d);
}
@Override
public int compareTo(String str) throws PageException {
return Operator.compare(castToString(), str);
}
public String getBaseURI() {
// not supported
return null;
}
public short compareDocumentPosition(Node other) throws DOMException {
// not supported
return -1;
}
public void setTextContent(String textContent) throws DOMException {
//TODO not supported
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,"this method is not supported");
}
public boolean isSameNode(Node other) {
return this==other;
}
public String lookupPrefix(String namespaceURI) {
// TODO not supported
return null;
}
public boolean isDefaultNamespace(String namespaceURI) {
// TODO not supported
return false;
}
public String lookupNamespaceURI(String prefix) {
// TODO not supported
return null;
}
public boolean isEqualNode(Node node) {
// TODO not supported
return this==node;
}
public Object getFeature(String feature, String version) {
// TODO not supported
return null;
}
public Object getUserData(String key) {
// dynamic load to support jre 1.4 and 1.5
try {
Method m = node.getClass().getMethod("getUserData", new Class[]{key.getClass()});
return m.invoke(node, new Object[]{key});
}
catch (Exception e) {
throw new PageRuntimeException(Caster.toPageException(e));
}
}
public String getTextContent() throws DOMException {
// dynamic load to support jre 1.4 and 1.5
try {
Method m = node.getClass().getMethod("getTextContent", new Class[]{});
return Caster.toString(m.invoke(node, ArrayUtil.OBJECT_EMPTY));
}
catch (Exception e) {
throw new PageRuntimeException(Caster.toPageException(e));
}
}
public Object setUserData(String key, Object data, UserDataHandler handler) {
// dynamic load to support jre 1.4 and 1.5
try {
Method m = node.getClass().getMethod("setUserData", new Class[]{key.getClass(),data.getClass(),handler.getClass()});
return m.invoke(node, new Object[]{key,data,handler});
}
catch (Exception e) {
throw new PageRuntimeException(Caster.toPageException(e));
}
}
public boolean isCaseSensitive() {
return caseSensitive;
}
public boolean equals(Object obj) {
if(!(obj instanceof XMLNodeStruct))
return super.equals(obj);
XMLNodeStruct other = ((XMLNodeStruct)obj);
return other.caseSensitive=caseSensitive && other.node.equals(node);
}
}