/*******************************************************************************
gocha.org-lib-java Библеотека общего назначения
(с) Камнев Георгий Павлович 2009 GPLv2
Данная программа является свободным программным обеспечением. Вы вправе
распространять ее и/или модифицировать в соответствии с условиями версии 2
либо по вашему выбору с условиями более поздней версии
Стандартной Общественной Лицензии GNU, опубликованной Free Software Foundation.
Мы распространяем данную программу в надежде на то, что она будет вам полезной,
однако НЕ ПРЕДОСТАВЛЯЕМ НА НЕЕ НИКАКИХ ГАРАНТИЙ,
в том числе ГАРАНТИИ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ
и ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ.
Для получения более подробной информации ознакомьтесь
со Стандартной Общественной Лицензией GNU.
Вместе с данной программой вы должны были получить экземпляр
Стандартной Общественной Лицензии GNU.
Если вы его не получили, сообщите об этом в Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*******************************************************************************/
package org.gocha.xml;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.gocha.types.DefaultTypesConvertors;
import org.gocha.types.PropertyController;
import org.gocha.types.ToValueConvertor;
import org.gocha.types.TypesConverters;
import org.gocha.types.ValueController;
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.xml.sax.SAXException;
/**
* @author gocha
*/
public class XMLDecoder
{
private static Map<String,Class> defTagMap = null;
private static boolean debug = false;
public static Map<String,Class> getDefaultTagMap()
{
if( defTagMap==null )
{
defTagMap = new HashMap<String, Class>();
}
return defTagMap;
}
private Map<String,Class> tagMap = null;
public Map<String,Class> getTagMap()
{
if( tagMap==null )
{
tagMap = new HashMap<String, Class>();
tagMap.putAll(getDefaultTagMap());
}
return tagMap;
}
private String keyMapAttribute = null;
public String getKeyMapAttribute()
{
if( keyMapAttribute==null )keyMapAttribute = "key";
return keyMapAttribute;
}
public void setKeyMapAttribute(String keyMapAttribute)
{
this.keyMapAttribute = keyMapAttribute;
}
private Class keyMapClass = String.class;
public Class getKeyMapClass()
{
return keyMapClass;
}
public void setKeyMapClass(Class keyMapClass)
{
this.keyMapClass = keyMapClass;
}
private Map<Class,Map<String,CustomAttributeSetter>> customAttributeSet = null;
public CustomAttributeSetter getAttributeSetter(Class cls,String attribute)
{
if( cls==null || attribute==null )return null;
if( customAttributeSet==null )return null;
if( !customAttributeSet.containsKey(cls) )return null;
Map<String,CustomAttributeSetter> m = customAttributeSet.get(cls);
if( m==null )return null;
for( String att : m.keySet() )
{
if( att==null )continue;
if( att.equalsIgnoreCase(attribute) )
return m.get(att);
}
return null;
}
public void removeCustomAttribute(Class cls)
{
putAttributeSetter(cls, null, null);
}
public void removeCustomAttribute(Class cls,String attribute)
{
putAttributeSetter(cls, attribute, null);
}
public void putAttributeSetter(Class cls,String attribute,CustomAttributeSetter setter)
{
if( cls==null )return;
if( attribute==null )
{
if( customAttributeSet==null )return;
if( customAttributeSet.containsKey(cls) )
customAttributeSet.remove(cls);
return;
}
if( setter==null )
{
if( customAttributeSet==null )return;
if( !customAttributeSet.containsKey(cls) )return;
Map<String,CustomAttributeSetter> m = customAttributeSet.get(cls);
if( m==null )return;
ArrayList<String> toDel = new ArrayList<String>();
for( String att : m.keySet() )
{
if( att==null )continue;
if( att.equalsIgnoreCase(attribute) )toDel.add(att);
}
for( String k : toDel )m.remove(k);
return;
}
if( customAttributeSet==null )
customAttributeSet = new HashMap<Class, Map<String, CustomAttributeSetter>>();
if( !customAttributeSet.containsKey(cls) )
customAttributeSet.put(cls, new HashMap<String, CustomAttributeSetter>());
Map<String,CustomAttributeSetter> m = customAttributeSet.get(cls);
if( !m.containsKey(attribute.toLowerCase()) )
{
m.put(attribute.toLowerCase(), setter);
}else{
for( String k : m.keySet() )
{
if( k==null )continue;
if( k.equalsIgnoreCase(attribute) )
m.put(k, setter);
}
}
}
public Object parseXML(String text) throws IOException, SAXException
{
if (text == null) {
throw new IllegalArgumentException("text == null");
}
Document doc = XMLUtil.parseXML(text);
if( doc!=null )return parse(doc);
return null;
}
public Object parse(Document xmlDoc)
{
if (xmlDoc == null) {
throw new IllegalArgumentException("xmlDoc == null");
}
Node docEl = xmlDoc.getDocumentElement();
if( docEl!=null )
{
Object o = parse(docEl);
return o;
}
return null;
}
public Object parse(Node xmlNode)
{
if (xmlNode == null) {
throw new IllegalArgumentException("xmlNode == null");
}
if( xmlNode instanceof Element )
return parse((Element)xmlNode);
return null;
}
public Object parse(Element xmlElement)
{
if (xmlElement == null) {
throw new IllegalArgumentException("xmlElement == null");
}
Object objTag = createObjectFromNode(xmlElement);
if( objTag==null )return null;
setAttributes(objTag, xmlElement);
parseChildren(objTag, xmlElement);
return objTag;
}
protected Object createObjectFromNode( Node xmlNode )
{
if (xmlNode == null) {
throw new IllegalArgumentException("xmlNode == null )");
}
if(!(xmlNode instanceof org.w3c.dom.Element))return null;
String name = xmlNode.getNodeName();
if( name==null )return null;
if( !getTagMap().containsKey(name.toLowerCase()) )return null;
Class cls = getTagMap().get(name.toLowerCase());
if( cls==null )return null;
Object objTag = null;
try {
Object obj = cls.newInstance();
objTag = obj;
}
catch (InstantiationException ex) {
ex.printStackTrace();
}
catch (IllegalAccessException ex) {
ex.printStackTrace();
}
onObjectCreated(objTag);
return objTag;
}
protected void onObjectCreated(Object obj)
{
}
protected void setAttributes( Object obj, Node node )
{
if( debug )System.out.println("set attributes to "+obj);
if( !node.hasAttributes() )
{
onSettedAttributes(obj);
return;
}
Map<String,ValueController> map1 = PropertyController.buildControllersMap(obj);
Map<String,ValueController> map = new HashMap<String, ValueController>();
for( String k : map1.keySet() )map.put(k.toLowerCase(), map1.get(k));
NamedNodeMap nnm = node.getAttributes();
if( nnm==null )
{
onSettedAttributes(obj);
return;
}
int count = nnm.getLength();
for( int i=0; i<count; i++ )
{
Node attr = nnm.item(i);
String attrName = attr.getNodeName();
String attrValue = attr.getNodeValue();
setAttribute( obj, map, attrName, attrValue);
}
onSettedAttributes(obj);
}
protected void onSettedAttributes(Object obj)
{
}
protected boolean customSetAttribute( Object obj, String attr, String value )
{
if( debug )System.out.println("custom set attribute "+attr+" = "+value);
CustomAttributeSetter setter = getAttributeSetter(obj.getClass(), attr);
if( setter!=null )
{
setter.set(obj, attr, value);
return true;
}
if( debug )System.out.println("custom attr NOT setted");
return false;
}
protected TypesConverters typesConverters = DefaultTypesConvertors.instance();
public TypesConverters getTypesConvertors()
{
if( typesConverters==null )typesConverters = DefaultTypesConvertors.instance();
return typesConverters;
}
public void setTypesConvertors(TypesConverters conv){
typesConverters = conv;
}
protected void setAttribute( Object obj, Map<String,ValueController> vcMap, String attrName, String attrValue)
{
if( debug )System.out.println("set attribute "+attrName+" = "+attrValue);
if( customSetAttribute(obj, attrName, attrValue) )
{
if( debug )System.out.println("custom attr setted");
return;
}else{
}
if( !vcMap.containsKey(attrName.toLowerCase()) )
{
if( debug )System.out.println("vcMap not has "+attrName.toLowerCase());
return;
}
ValueController vc = vcMap.get(attrName.toLowerCase());
ToValueConvertor conv = getTypesConvertors().toValueFor(vc.getType());
if( conv==null )
return;
Object destValue = null;
try
{
destValue = conv.convertToValue(attrValue);
vc.setValue(destValue);
if( debug )System.out.println("attr Setted");
}
catch(Throwable e)
{
e.printStackTrace();
return;
}
}
private Map<Class,CustomChildrenParser> customChildrenParsers = null;
public CustomChildrenParser getChildrenParserForObject(Object obj)
{
if( customChildrenParsers==null )return null;
if( obj==null )return null;
Class cls = obj.getClass();
if( !customChildrenParsers.containsKey(cls) )return null;
CustomChildrenParser parser = customChildrenParsers.get(cls);
return parser;
}
public void putChildrenParser(Class cls,CustomChildrenParser parser)
{
if( cls==null )return;
if( parser==null )
{
if( customChildrenParsers==null )return;
// ArrayList<Class> toDel = new ArrayList<Class>();
// for( Class c : customChildrenParsers.keySet() )
// {
// if( c==null )continue;
// if( c.equals(cls) )
// {
// toDel.add(c);
// }
// }
//
// for( Class c : toDel )customChildrenParsers.remove(c);
customChildrenParsers.remove(cls);
return;
}
if( customChildrenParsers==null )
customChildrenParsers = new HashMap<Class, CustomChildrenParser>();
customChildrenParsers.put(cls, parser);
}
public void removeCustomChildrenParser(Class cls)
{
if( cls==null )return;
putChildrenParser(cls, null);
}
protected boolean customParseChildren( Object parentObject, Node parentNode )
{
CustomChildrenParser parser = getChildrenParserForObject(parentObject);
if( parser!=null )
{
parser.parse(parentObject, parentNode);
return true;
}
return false;
}
protected void parseChildren( Object parentObject, Node parentNode )
{
if( customParseChildren(parentObject, parentNode) )
return;
if( !parentNode.hasChildNodes() )
{
onChildrenAdded(parentObject);
return;
}
if( parentObject instanceof Collection )
{
parseChildrenList(parentObject, parentNode);
return;
}
if( parentObject instanceof Map )
{
parseChildrenMap(parentObject, parentNode);
return;
}
onChildrenAdded(parentObject);
}
protected void parseChildrenMap( Object parentObject, Node parentNode )
{
String keyAttr = getKeyMapAttribute();
Class keyClass = getKeyMapClass();
TypesConverters conv = DefaultTypesConvertors.instance();
ToValueConvertor toValue = keyClass==null ? null : conv.toValueFor(keyClass);
if( !parentNode.hasChildNodes() ||
!(parentObject instanceof Map) ||
keyAttr==null || keyAttr.length()<1 ||
keyClass==null ||
toValue==null
)
{
onChildrenAdded(parentObject);
return;
}
NodeList nl = parentNode.getChildNodes();
int count = nl.getLength();
for( int i=0; i<count; i++ )
{
Node childNode = nl.item(i);
if( childNode==null )continue;
if( !childNode.hasAttributes() )continue;
Node keyNode = childNode.getAttributes().getNamedItem(keyAttr);
if( keyNode==null )continue;
String keyValueString = keyNode.getNodeValue();
if( keyValueString==null )continue;
try
{
Object keyObject = toValue.convertToValue(keyValueString);
if( keyObject==null )continue;
Object childObject = parse(childNode);
if( childObject!=null )
{
((Map)parentObject).put(keyObject, childObject);
}
}
catch(Throwable e)
{
e.printStackTrace();
}
}
onChildrenAdded(parentObject);
}
protected void parseChildrenList( Object parentObject, Node parentNode )
{
if( !parentNode.hasChildNodes() )
{
onChildrenAdded(parentObject);
return;
}
if( !(parentObject instanceof Collection) )
{
onChildrenAdded(parentObject);
return;
}
NodeList nl = parentNode.getChildNodes();
int count = nl.getLength();
for( int i=0; i<count; i++ )
{
Node childNode = nl.item(i);
Object childObject = parse(childNode);
if( childObject!=null )
{
((Collection)parentObject).add(childObject);
}
}
onChildrenAdded(parentObject);
}
protected void onChildrenAdded(Object obj)
{
}
}