001: /*
002: * hgcommons 7
003: * Hammurapi Group Common Library
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.xml.dom;
024:
025: import java.lang.reflect.Field;
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Modifier;
028: import java.util.HashMap;
029: import java.util.HashSet;
030: import java.util.Map;
031: import java.util.Set;
032:
033: import org.w3c.dom.Element;
034:
035: import biz.hammurapi.xml.dom.CompositeDomSerializer.Member;
036:
037: /**
038: * @author Pavel Vlasov
039: *
040: * @version $Revision: 1.4 $
041: */
042: public class BeanDomSerializer implements Member {
043: private class StackEntry {
044: long counter;
045:
046: private class IdentityWrapper {
047: Object o;
048:
049: public IdentityWrapper(Object o) {
050: this .o = o;
051: }
052:
053: public int hashCode() {
054: return o.hashCode();
055: }
056:
057: public boolean equals(Object obj) {
058: return obj instanceof IdentityWrapper
059: && o == ((IdentityWrapper) obj).o;
060: }
061: }
062:
063: Map identityMap = new HashMap();
064: Map referenceMap = new HashMap();
065:
066: Long getReference(Object o) {
067: if (o instanceof Number || o instanceof String) {
068: return (Long) referenceMap.get(o);
069: }
070:
071: return (Long) identityMap.get(new IdentityWrapper(o));
072: }
073:
074: long addReference(Object o) {
075: if (o instanceof Number || o instanceof String) {
076: Long ref = (Long) referenceMap.get(o);
077: if (ref == null) {
078: long next = counter++;
079: referenceMap.put(o, new Long(next));
080: return next;
081: }
082:
083: return ref.longValue();
084: }
085:
086: IdentityWrapper iw = new IdentityWrapper(o);
087:
088: Long ref = (Long) identityMap.get(iw);
089: if (ref == null) {
090: long next = counter++;
091: identityMap.put(iw, new Long(next));
092: return next;
093: }
094:
095: return ref.longValue();
096: }
097: }
098:
099: private static ThreadLocal stack = new ThreadLocal();
100:
101: private CompositeDomSerializer owner;
102:
103: private Set badMethods = new HashSet();
104:
105: public DomSerializable toDomSerializable(final Object object) {
106: if (object != null) {
107: return new DomSerializable() {
108:
109: public void toDom(Element holder) {
110: if (object instanceof Class) {
111: holder.appendChild(holder.getOwnerDocument()
112: .createTextNode(
113: ((Class) object).getName()));
114: return;
115: }
116:
117: StackEntry sEntry = (StackEntry) stack.get();
118: boolean clean = sEntry == null;
119: if (clean) {
120: sEntry = new StackEntry();
121: stack.set(sEntry);
122: }
123:
124: try {
125:
126: Long refId = sEntry.getReference(object);
127: if (refId != null) {
128: holder.setAttribute("refid", refId
129: .toString());
130: return;
131: }
132:
133: long nextCounter = sEntry.addReference(object);
134: //System.out.println("New id: "+nextCounter);
135: holder.setAttribute("id", String
136: .valueOf(nextCounter));
137:
138: holder.setAttribute("type", object.getClass()
139: .getName());
140: holder.appendChild(holder.getOwnerDocument()
141: .createTextNode(object.toString()));
142:
143: if (owner != null) {
144: Class beanClass = object.getClass();
145: final Object[] args = new Object[] {};
146: Method[] methods = beanClass.getMethods();
147: for (int i = 0; i < methods.length; i++) {
148: // getXXX() methods. Object.getClass() is not included.
149: Method method = methods[i];
150: if (!(void.class.equals(method
151: .getReturnType()))
152: && Modifier.isPublic(method
153: .getModifiers())
154: && !Modifier.isAbstract(method
155: .getModifiers())
156: && !(method.getDeclaringClass()
157: .equals(Object.class))
158: && !Modifier.isStatic(method
159: .getModifiers())
160: && method.getName().startsWith(
161: "get")
162: && method.getParameterTypes().length == 0
163: && !isBad(method)) {
164: try {
165: Object value = method.invoke(
166: object, args);
167: if (value != object) {
168: DomSerializable vds = owner
169: .getStackHead()
170: .toDomSerializable(
171: value);
172: if (vds != null) {
173: Element ve = holder
174: .getOwnerDocument()
175: .createElement(
176: method
177: .getName()
178: .substring(
179: 3));
180: holder.appendChild(ve);
181: vds.toDom(ve);
182: }
183: }
184: } catch (Exception e) {
185: synchronized (badMethods) {
186: badMethods.add(method);
187: }
188: handleAccessError(holder,
189: method, e);
190: }
191: }
192: }
193:
194: Field[] fields = beanClass.getFields();
195: for (int i = 0; i < fields.length; i++) {
196: Field field = fields[i];
197: if (!Modifier.isStatic(field
198: .getModifiers())
199: && Modifier.isPublic(field
200: .getModifiers())) {
201: try {
202: Object value = field
203: .get(object);
204: DomSerializable vds = owner
205: .getStackHead()
206: .toDomSerializable(
207: value);
208: if (vds != null) {
209: Element ve = holder
210: .getOwnerDocument()
211: .createElement(
212: field
213: .getName());
214: holder.appendChild(ve);
215: vds.toDom(ve);
216: }
217: } catch (Exception e) {
218: handleAccessError(holder,
219: field, e);
220: }
221: }
222: }
223: }
224: } finally {
225: if (clean) {
226: stack.set(null);
227: }
228: }
229: }
230:
231: private boolean isBad(Method method) {
232: synchronized (badMethods) {
233: return badMethods.contains(method);
234: }
235: }
236: };
237: }
238:
239: return null;
240: }
241:
242: /**
243: * Callback method
244: */
245: public void setOwner(CompositeDomSerializer owner) {
246: this .owner = owner;
247: }
248:
249: private void handleAccessError(Element holder,
250: java.lang.reflect.Member member, Throwable e) {
251: Element ee = holder.getOwnerDocument().createElement(
252: "access-error");
253: holder.appendChild(ee);
254: ee.setAttribute("member", member.toString());
255: DomSerializable eds = owner.getStackHead().toDomSerializable(e);
256: eds.toDom(ee);
257: }
258: }
|