001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.xml.dom; 005 006 import java.lang.reflect.Field; 007 import java.lang.reflect.Method; 008 import java.lang.reflect.Modifier; 009 import java.util.HashMap; 010 import java.util.HashSet; 011 import java.util.Map; 012 import java.util.Set; 013 014 import org.w3c.dom.Element; 015 016 import biz.hammurapi.xml.dom.CompositeDomSerializer.Member; 017 018 /** 019 * @author Pavel Vlasov 020 * 021 * @version $Revision: 1.4 $ 022 */ 023 public class BeanDomSerializer implements Member { 024 private class StackEntry { 025 long counter; 026 027 private class IdentityWrapper { 028 Object o; 029 030 public IdentityWrapper(Object o) { 031 this.o=o; 032 } 033 034 public int hashCode() { 035 return o.hashCode(); 036 } 037 038 public boolean equals(Object obj) { 039 return obj instanceof IdentityWrapper && o==((IdentityWrapper) obj).o; 040 } 041 } 042 043 Map identityMap=new HashMap(); 044 Map referenceMap=new HashMap(); 045 046 Long getReference(Object o) { 047 if (o instanceof Number || o instanceof String) { 048 return (Long) referenceMap.get(o); 049 } 050 051 return (Long) identityMap.get(new IdentityWrapper(o)); 052 } 053 054 long addReference(Object o) { 055 if (o instanceof Number || o instanceof String) { 056 Long ref=(Long) referenceMap.get(o); 057 if (ref==null) { 058 long next=counter++; 059 referenceMap.put(o, new Long(next)); 060 return next; 061 } 062 063 return ref.longValue(); 064 } 065 066 IdentityWrapper iw = new IdentityWrapper(o); 067 068 Long ref=(Long) identityMap.get(iw); 069 if (ref==null) { 070 long next=counter++; 071 identityMap.put(iw, new Long(next)); 072 return next; 073 } 074 075 return ref.longValue(); 076 } 077 } 078 079 private static ThreadLocal stack=new ThreadLocal(); 080 081 private CompositeDomSerializer owner; 082 083 private Set badMethods=new HashSet(); 084 085 public DomSerializable toDomSerializable(final Object object) { 086 if (object!=null) { 087 return new DomSerializable() { 088 089 public void toDom(Element holder) { 090 if (object instanceof Class) { 091 holder.appendChild(holder.getOwnerDocument().createTextNode(((Class) object).getName())); 092 return; 093 } 094 095 StackEntry sEntry=(StackEntry) stack.get(); 096 boolean clean = sEntry==null; 097 if (clean) { 098 sEntry=new StackEntry(); 099 stack.set(sEntry); 100 } 101 102 try { 103 104 Long refId=sEntry.getReference(object); 105 if (refId!=null) { 106 holder.setAttribute("refid", refId.toString()); 107 return; 108 } 109 110 long nextCounter = sEntry.addReference(object); 111 //System.out.println("New id: "+nextCounter); 112 holder.setAttribute("id", String.valueOf(nextCounter)); 113 114 holder.setAttribute("type", object.getClass().getName()); 115 holder.appendChild(holder.getOwnerDocument().createTextNode(object.toString())); 116 117 if (owner!=null) { 118 Class beanClass=object.getClass(); 119 final Object[] args = new Object[] {}; 120 Method[] methods = beanClass.getMethods(); 121 for (int i=0; i<methods.length; i++) { 122 // getXXX() methods. Object.getClass() is not included. 123 Method method = methods[i]; 124 if (!(void.class.equals(method.getReturnType())) 125 && Modifier.isPublic(method.getModifiers()) 126 && !Modifier.isAbstract(method.getModifiers()) 127 && !(method.getDeclaringClass().equals(Object.class)) 128 && !Modifier.isStatic(method.getModifiers()) 129 && method.getName().startsWith("get") 130 && method.getParameterTypes().length==0 131 && !isBad(method)) { 132 try { 133 Object value=method.invoke(object, args); 134 if (value!=object) { 135 DomSerializable vds=owner.getStackHead().toDomSerializable(value); 136 if (vds!=null) { 137 Element ve=holder.getOwnerDocument().createElement(method.getName().substring(3)); 138 holder.appendChild(ve); 139 vds.toDom(ve); 140 } 141 } 142 } catch (Exception e) { 143 synchronized (badMethods) { 144 badMethods.add(method); 145 } 146 handleAccessError(holder, method, e); 147 } 148 } 149 } 150 151 Field[] fields = beanClass.getFields(); 152 for (int i=0; i<fields.length; i++) { 153 Field field = fields[i]; 154 if (!Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers())) { 155 try { 156 Object value=field.get(object); 157 DomSerializable vds=owner.getStackHead().toDomSerializable(value); 158 if (vds!=null) { 159 Element ve=holder.getOwnerDocument().createElement(field.getName()); 160 holder.appendChild(ve); 161 vds.toDom(ve); 162 } 163 } catch (Exception e) { 164 handleAccessError(holder, field, e); 165 } 166 } 167 } 168 } 169 } finally { 170 if (clean) { 171 stack.set(null); 172 } 173 } 174 } 175 176 private boolean isBad(Method method) { 177 synchronized (badMethods) { 178 return badMethods.contains(method); 179 } 180 } 181 }; 182 } 183 184 return null; 185 } 186 187 /** 188 * Callback method 189 */ 190 public void setOwner(CompositeDomSerializer owner) { 191 this.owner=owner; 192 } 193 194 private void handleAccessError(Element holder, java.lang.reflect.Member member, Throwable e) { 195 Element ee=holder.getOwnerDocument().createElement("access-error"); 196 holder.appendChild(ee); 197 ee.setAttribute("member", member.toString()); 198 DomSerializable eds=owner.getStackHead().toDomSerializable(e); 199 eds.toDom(ee); 200 } 201 }