/*
* eGov suite of products aim to improve the internal efficiency,transparency,
* accountability and the service delivery of the government organizations.
*
* Copyright (C) <2015> eGovernments Foundation
*
* The updated version of eGov suite of products as by eGovernments Foundation
* is available at http://www.egovernments.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program 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 this program. If not, see http://www.gnu.org/licenses/ or
* http://www.gnu.org/licenses/gpl.html .
*
* In addition to the terms of the GPL license to be adhered to in using this
* program, the following additional terms are to be complied with:
*
* 1) All versions of this program, verbatim or modified must carry this
* Legal Notice.
*
* 2) Any misrepresentation of the origin of the material is prohibited. It
* is required that all modified versions of this material be marked in
* reasonable ways as different from the original version.
*
* 3) This license does not grant any rights to any user of the program
* with regards to rights under trademark law for use of the trade names
* or trademarks of eGovernments Foundation.
*
* In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org.
*/
package com.exilant.exility.common;
import org.apache.log4j.Logger;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @author raghu.bhandi
*
* Generates XML string for an object. This is a singleton, as there is no need to have any instance variables
*/
public class XMLGenerator {
// this is a singleton.
private static XMLGenerator xmlGenerator = null;
private static final Logger LOGGER = Logger.getLogger(XMLGenerator.class);
/**
*
*/
private XMLGenerator() {
}
public static XMLGenerator getInstance() {
if (xmlGenerator == null)
xmlGenerator = new XMLGenerator();
return xmlGenerator;
}
/*
* Generate XML for any object. Note: this method is plymorphed for specific types of class
*/
public String toXML(final Object object, String tag, final String tabs) {
final Class objclass = object.getClass();
/*
* If the class designer is smart enough to write her own toXML(String tag, String tabs)...
*/
final Class[] clsarr = { String.class, String.class };
final Object[] objarr = { tag, tabs };
try {
final Method method = objclass.getMethod("toXML", clsarr);
method.setAccessible(true);
return (String) method.invoke(object, objarr);
} catch (final Exception e) {
if (LOGGER.isInfoEnabled())
LOGGER.info("Failed to invoke method" + e.getMessage());
} // no sweat if you failed. Carry on...
final StringBuffer sbf = new StringBuffer(tabs);
// set tag if required
if (tag == null || tag.length() == 0)
try {
tag = ObjectGetSetter.get(object, "type").toString(); // try type field for tag
} catch (final Exception e) {
LOGGER.error("Error in toXML" + e.getMessage());
}
if (tag == null || tag.length() == 0) {
tag = object.getClass().getName();
tag = tag.substring(tag.lastIndexOf('.') + 1);
tag = tag.substring(0, 1).toLowerCase() + tag.substring(1);
}
// produce "<tag "
sbf.append('<');
sbf.append(tag);
sbf.append(' ');
if (objclass.isPrimitive() || objclass.getName().indexOf("java.lang.") == 0) {
sbf.append("value=\"");
sbf.append(object.toString());
sbf.append("\"/>\n");
} else if (objclass.isArray())
sbf.append(arrayToXML(object, tag, tabs));
else if (objclass.equals(HashMap.class))
sbf.append(hashMapToXML((HashMap) object, tag, tabs));
else if (objclass.equals(ArrayList.class))
sbf.append(arrayListToXML((ArrayList) object, tag, tabs));
else {
final HashMap values = ObjectGetSetter.getAll(object, false);
sbf.append(hashMapToXML(values, tag, tabs));
}
return sbf.toString();
}
/*****************************************
* Helper classes declared as private
****************************************/
/*
* returns XML String for an array object with name as tag
*/
private String arrayToXML(final Object object, final String tag, final String tabs) {
final StringBuffer sbf = new StringBuffer();
sbf.append("class=\"Array\" length=\"");
final int len = Array.getLength(object);
sbf.append(len);
sbf.append("\" ");
if (len == 0) {
sbf.append("/>\n"); // end of tag and line
return sbf.toString();
}
// Look at the type of elements the array contains
final Class cls = object.getClass().getComponentType();
String newtag;
if (cls.isArray())
newtag = "Array_" + cls.getComponentType();
else {
newtag = cls.getName();
newtag = newtag.substring(newtag.lastIndexOf(".") + 1);
newtag = newtag.substring(0, 1).toLowerCase() + newtag.substring(1);
}
// produce class="class" and close tag
sbf.append(" type=\"");
sbf.append(newtag);
sbf.append("\">\n");
final String newtabs = tabs + '\t'; // additional indent for children
if (cls.isPrimitive() || cls.getName().indexOf("java.lang.") == 0)
// dump elements <class index="i" value="value"/>
for (int i = 0; i < len; i++) {
sbf.append(newtabs);
sbf.append('<');
sbf.append(newtag);
sbf.append(" index=\"");
sbf.append(i);
sbf.append("\" value=\"");
sbf.append(Array.get(object, i));
sbf.append("\" />\n");
}
else {
// generate XML for each element
final XMLGenerator xg = XMLGenerator.getInstance();
for (int i = 0; i < len; i++)
sbf.append(xg.toXML(Array.get(object, i), newtag, newtabs));
}
sbf.append(tabs);
sbf.append('<');
sbf.append(tag);
sbf.append("/>\n");
return sbf.toString();
}
/*
* returns XML string for an Object that is a HashMap. It treats all primitive (primitive + String, Integer etc..) as
* attributes and other elements as 'children'
*/
private String hashMapToXML(final HashMap object, final String tag, final String tabs) {
final StringBuffer sbf = new StringBuffer();
boolean childfound = false;
Iterator iterator;
Map.Entry entry;
String key;
Object obj;
Class cls;
iterator = object.entrySet().iterator();
while (iterator.hasNext()) {
entry = (Map.Entry) iterator.next();
obj = entry.getKey();
if (!obj.getClass().equals(String.class))
continue; // key has to be string
key = (String) obj;
obj = entry.getValue();
if (obj == null)
continue;
cls = obj.getClass();
if (cls.isPrimitive() || cls.getName().indexOf("java.lang.") == 0) { // attribute
sbf.append(key);
sbf.append("=\"");
sbf.append(entry.getValue().toString());
sbf.append("\" ");
} else
childfound = true;
}
if (childfound) {
// close line but not tag. ie. produce > and not />
sbf.append(">\n");
// lat us add XML for children
final String newtabs = tabs + '\t';
final XMLGenerator xg = XMLGenerator.getInstance();
final Iterator newIter = object.entrySet().iterator();
Map.Entry newEntry;
while (newIter.hasNext()) {
newEntry = (Map.Entry) newIter.next();
obj = newEntry.getKey();
if (!obj.getClass().equals(String.class))
continue; // key has to be string
key = (String) obj;
obj = newEntry.getValue();
if (obj == null)
continue;
if (obj.getClass().isPrimitive() || obj.getClass().getName().indexOf("java.lang.") == 0)
continue; // attribute
sbf.append(xg.toXML(newEntry.getValue(), key, newtabs));
}
sbf.append(tabs);
sbf.append('<');
sbf.append(tag);
sbf.append("/>\n");
} else
sbf.append("/>\n");
return sbf.toString();
}
/*
* returns XML string for an Object that is a HashMap. It treats all primitive (primitive + String, Integer etc..) as
* attributes and other elements as 'children'
*/
private String arrayListToXML(final ArrayList object, final String tag, final String tabs) {
final int size = object.size();
final StringBuffer sbf = new StringBuffer();
// produce header tag as <tag class="ArrayList" size="size>;
sbf.append(" class=\"ArrayList\" size=\""); // problem with java. array-length, arraylist-size
sbf.append(size);
sbf.append("\" ");
if (size == 0)
sbf.append("/>\n");
else {
sbf.append(">\n");
final XMLGenerator xg = XMLGenerator.getInstance();
final String newtabs = tabs + '\t';
for (int i = 0; i < size; i++)
sbf.append(xg.toXML(object.get(i), null, newtabs));
sbf.append(tabs);
sbf.append('<');
sbf.append(tag);
sbf.append("/>\n");
}
return sbf.toString();
}
}