/* * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.xml.object; import org.exoplatform.commons.utils.ClassLoading; import org.exoplatform.commons.utils.SecurityHelper; import org.exoplatform.container.xml.Configuration; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.jibx.runtime.BindingDirectory; import org.jibx.runtime.IBindingFactory; import org.jibx.runtime.IMarshallingContext; import org.jibx.runtime.IUnmarshallingContext; import org.jibx.runtime.JiBXException; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * @author Tuan Nguyen (tuan08@users.sourceforge.net) * @since Apr 10, 2005 * @version $Id: XMLObject.java 11659 2007-01-05 15:35:06Z geaz $ */ public class XMLObject { /** * The logger */ private static final Log LOG = ExoLogger.getLogger("exo.kernel.container.XMLObject"); public static String CURRENT_VERSION = "1.0"; static Map<Class<?>, Map<String, Field>> cacheFields_ = new HashMap<Class<?>, Map<String, Field>>(); private Map<String, XMLField> fields_ = new HashMap<String, XMLField>(); private String type; public XMLObject() { } public XMLObject(Object obj) throws Exception { Class<?> clazz = obj.getClass(); Map<String, Field> fields = getFields(clazz); setType(obj.getClass().getName()); Iterator<Field> i = fields.values().iterator(); while (i.hasNext()) { Field field = i.next(); Object value = field.get(obj); if (value == null || (!value.getClass().isPrimitive() && Configuration.hasComponent(field.getType().getName()))) { // The current field is a component so we ignore it or its value is null continue; } addField(new XMLField(field.getName(), field.getType(), value)); } } public String getType() { return type; } public void setType(String s) { type = s; } public XMLField getField(String name) { return fields_.get(name); } public void addField(Object o) { XMLField field = (XMLField)o; fields_.put(field.getName(), field); } public void addField(XMLField field) { fields_.put(field.getName(), field); } public Iterator<XMLField> getFieldIterator() { return fields_.values().iterator(); } public Collection<XMLField> getFields() { return fields_.values(); } public void setFields(Collection<XMLField> fields) { Iterator<XMLField> i = fields.iterator(); while (i.hasNext()) { XMLField field = i.next(); fields_.put(field.getName(), field); } } public void setFields(Map<String, XMLField> fields) { fields_.putAll(fields); } public Object getFieldValue(String fieldName) throws Exception { XMLField field = fields_.get(fieldName); if (field != null) return field.getObjectValue(); return null; } public void renameField(String oldName, String newName) { XMLField field = fields_.remove(oldName); field.setName(newName); fields_.put(newName, field); } public void removeField(String name) { fields_.remove(name); } public void addField(String name, Class<?> fieldType, Object obj) throws Exception { addField(new XMLField(name, fieldType, obj)); } @Override public String toString() { StringBuffer b = new StringBuffer(); b.append("type: ").append(type).append("\n"); Iterator<XMLField> i = fields_.values().iterator(); while (i.hasNext()) { XMLField field = i.next(); b.append(field.toString()).append("\n"); } return b.toString(); } public Object toObject() throws Exception { Class<?> clazz = ClassLoading.forName(type, this); Map<String, Field> fields = getFields(clazz); Object instance = clazz.newInstance(); Iterator<XMLField> i = fields_.values().iterator(); while (i.hasNext()) { XMLField xmlfield = i.next(); try { Object value = xmlfield.getObjectValue(); Field field = fields.get(xmlfield.getName()); field.set(instance, value); } catch (Exception ex) { LOG.error("ERROR: Cannot set field: " + xmlfield.getName() + " of " + type, ex); throw ex; } } return instance; } public String toXML() throws Exception { return toXML("UTF-8"); } public String toXML(String encoding) throws Exception { return new String(toByteArray(encoding), encoding); } public byte[] toByteArray() throws Exception { return toByteArray("UTF-8"); } public byte[] toByteArray(String encoding) throws Exception { IBindingFactory bfact = getBindingFactoryInPriviledgedMode(XMLObject.class); IMarshallingContext mctx = bfact.createMarshallingContext(); mctx.setIndent(2); ByteArrayOutputStream os = new ByteArrayOutputStream(); mctx.marshalDocument(this, encoding, null, os); return os.toByteArray(); } public static XMLObject getXMLObject(InputStream is) throws Exception { IBindingFactory bfact = getBindingFactoryInPriviledgedMode(XMLObject.class); IUnmarshallingContext uctx = bfact.createUnmarshallingContext(); XMLObject xmlobject = (XMLObject)uctx.unmarshalDocument(is, "UTF-8"); return xmlobject; } public static Object getObject(InputStream is) throws Exception { return getXMLObject(is).toObject(); } static Map<String, Field> getFields(Class<?> clazz) { Map<String, Field> fields = (Map<String, Field>)cacheFields_.get(clazz); if (fields != null) return fields; synchronized (cacheFields_) { fields = new HashMap<String, Field>(); findFields(fields, clazz); cacheFields_.put(clazz, fields); } return fields; } static void findFields(Map<String, Field> fields, Class<?> clazz) { if (clazz.getName().startsWith("java.lang")) return; findFields(fields, clazz.getSuperclass()); Field[] field = clazz.getDeclaredFields(); for (int i = 0; i < field.length; i++) { int modifier = field[i].getModifiers(); if (Modifier.isStatic(modifier) || Modifier.isTransient(modifier)) continue; final Field fld = field[i]; SecurityHelper.doPrivilegedAction(new PrivilegedAction<Void>() { public Void run() { fld.setAccessible(true); return null; } }); fields.put(field[i].getName(), field[i]); } } protected static IBindingFactory getBindingFactoryInPriviledgedMode(final Class<?> clazz) throws JiBXException { try { return SecurityHelper.doPrivilegedExceptionAction(new PrivilegedExceptionAction<IBindingFactory>() { public IBindingFactory run() throws Exception { return BindingDirectory.getFactory(clazz); } }); } catch (PrivilegedActionException pae) { Throwable cause = pae.getCause(); if (cause instanceof JiBXException) { throw (JiBXException)cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException)cause; } else { throw new RuntimeException(cause); } } } }