/*
* Copyright (C) 2000 - 2011 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://www.openbluedragon.org/
*
* $Id: XmlHashtable.java 2497 2015-02-02 01:53:48Z alan $
*/
package com.naryx.tagfusion.cfm.xml;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.w3c.dom.DOMException;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.nary.util.CaseSensitiveMap;
import com.naryx.tagfusion.cfm.engine.cfData;
import com.naryx.tagfusion.cfm.engine.cfStringData;
import com.naryx.tagfusion.cfm.tag.cfDUMP;
public abstract class XmlHashtable implements CaseSensitiveMap,Serializable {
private static final long serialVersionUID = -5659752826018322960L;
protected Node nodeData = null;
private boolean isCaseSensitive;
protected XmlHashtable(Node n, boolean caseSensitive) {
nodeData = n;
isCaseSensitive = caseSensitive;
}
public Node getXMLNode() {
return nodeData;
}
public boolean isCaseSensitive() {
return isCaseSensitive;
}
public void dump(PrintWriter out) {
dump(out, "", cfDUMP.TOP_DEFAULT);
}
public abstract void dump(PrintWriter out, String _label, int _top);
public void dumpLong(PrintWriter out) {
dumpLong(out, "", cfDUMP.TOP_DEFAULT);
}
public abstract void dumpLong(PrintWriter out, String _label, int _top);
public boolean containsKey(Object key) {
NodeList nl = nodeData.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
if (equalKeys(nl.item(i).getNodeName(), (String) key))
return true;
}
return false;
}
public Object get(Object key) {
NodeList nl = nodeData.getChildNodes();
// Try elements first
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
Node node = nl.item(i);
if (equalKeys(node.getNodeName(), (String) key))
return new cfXmlData(this, node, isCaseSensitive);
}
}
// OK, try every other type of node then
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i).getNodeType() != Node.ELEMENT_NODE) {
Node node = nl.item(i);
if (equalKeys(node.getNodeName(), (String) key))
return new cfXmlData(this, node, isCaseSensitive);
}
}
return null;
}
public Set keySet() {
NodeList nl = nodeData.getChildNodes();
Set rtn = new HashSet(nl.getLength());
for (int i = 0; i < nl.getLength(); i++)
rtn.add(nl.item(i).getNodeName());
return rtn;
}
public Collection values() {
NodeList nl = nodeData.getChildNodes();
Set rtn = new HashSet(nl.getLength());
for (int i = 0; i < nl.getLength(); i++)
rtn.add(nl.item(i));
return rtn;
}
public Set entrySet() {
NodeList nl = nodeData.getChildNodes();
Set rtn = new HashSet(nl.getLength());
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
rtn.add(new Entry(node.getNodeName(), node));
}
return rtn;
}
public void putAll(Map map) {
Iterator itr = map.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
put(entry.getKey(), entry.getValue());
}
}
public Object put(Object key, Object value) {
try {
if (value instanceof cfXmlData) {
Node n = ((cfXmlData) value).getXMLNode();
if (n.getParentNode() != null)
n = n.cloneNode(true);
cfData d = (cfData) get(key);
if (d != null)
return nodeData.replaceChild(n, ((cfXmlData) d).getXMLNode());
else
nodeData.appendChild(n);
nodeData.normalize();
} else if (value instanceof cfStringData) {
if (((cfData) value).toString().trim().equals("")) {
cfXmlData d = (cfXmlData) get(key);
if (d != null)
nodeData.removeChild(d.getXMLNode());
nodeData.normalize();
}
}
} catch (DOMException ex) {
// Nothing else we can do here
com.nary.Debug.printStackTrace(ex);
}
return null;
}
public void clear() {
List toRemove = null;
Iterator itr = null;
try {
NodeList nl = nodeData.getChildNodes();
if (nl != null) {
// Get all the children
toRemove = new ArrayList(nl.getLength());
for (int i = 0; i < nl.getLength(); i++)
toRemove.add(nl.item(i));
// Now remove them
itr = toRemove.iterator();
while (itr.hasNext())
nodeData.removeChild((Node) itr.next());
}
NamedNodeMap attribs = nodeData.getAttributes();
if (attribs != null) {
// Get all the attributes
toRemove = new ArrayList(nl.getLength());
for (int i = 0; i < attribs.getLength(); i++)
toRemove.add(new String[] { attribs.item(i).getNamespaceURI(), attribs.item(i).getLocalName() });
// Now remove them
itr = toRemove.iterator();
while (itr.hasNext()) {
String[] attrib = (String[]) itr.next();
if (attrib[0] == null)
attribs.removeNamedItem(attrib[1]);
else
attribs.removeNamedItemNS(attrib[0], attrib[1]);
}
}
} catch (DOMException ex) {
// Nothing else we can do here
com.nary.Debug.printStackTrace(ex);
}
}
public Object remove(Object key) {
try {
cfData d = (cfData) get(key);
if (d != null) {
nodeData.removeChild(((cfXmlData) d).getXMLNode());
nodeData.normalize();
}
} catch (DOMException ex) {
// Nothing else we can do here
com.nary.Debug.printStackTrace(ex);
}
return null;
}
// Utility comparison method
protected boolean equalKeys(String k1, String k2) {
return (isCaseSensitive ? k1.equals(k2) : k1.equalsIgnoreCase(k2));
}
public int size() {
return nodeData.getChildNodes().getLength();
}
public boolean isEmpty() {
return nodeData.hasChildNodes();
}
private class Entry implements Map.Entry {
private Object k = null;
private Object v = null;
public Entry(Object k, Object v) {
this.k = k;
this.v = v;
}
public boolean equals(Object o) {
boolean rtn = (o instanceof Entry && o != null && ((Entry) o).getKey().equals(getKey()));
if (rtn) {
if (getValue() != null) {
if (((Entry) o).getValue() != null)
return ((Entry) o).getValue().equals(getValue());
else
return false;
} else {
if (((Entry) o).getValue() != null)
return false;
else
return true;
}
} else {
return false;
}
}
public Object getValue() {
return v;
}
public Object getKey() {
return k;
}
public Object setValue(Object val) {
Object rtn = v;
v = val;
return rtn;
}
public int hashCode() {
return getKey().hashCode();
}
}
}