001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.test;
022:
023: /*
024: * Author: Carl Rosenberger
025: *
026: * You may use this code in any way you wish, as
027: * long as you don't remove the following notice:
028: *
029: * Code written for:
030: * http://www.db4o.com
031: * http://sourceforge.net/projects/sodaquery
032: */
033: import java.lang.reflect.*;
034: import java.util.*;
035:
036: import com.db4o.internal.*;
037:
038: public class DeepCompare {
039:
040: public boolean isEqual(Object a_compare, Object a_with) {
041: return isEqual(a_compare, a_with, null, null);
042: }
043:
044: public boolean isEqual(Object a_compare, Object a_with,
045: String a_path, Stack a_stack) {
046: if (a_path == null || a_path.length() < 1) {
047: if (a_compare != null) {
048: a_path = a_compare.getClass().getName() + ":";
049: } else {
050: if (a_with != null) {
051: a_path = a_with.getClass().getName() + ":";
052: }
053: }
054: }
055:
056: String path = a_path;
057:
058: if (a_compare == null) {
059: return a_with == null;
060: }
061: if (a_with == null) {
062: return false;
063: }
064: Class clazz = a_compare.getClass();
065: if (clazz != a_with.getClass()) {
066: return false;
067: }
068:
069: if (isSimple(clazz)) {
070: return a_compare.equals(a_with);
071: }
072:
073: if (a_stack == null) {
074: a_stack = new Stack();
075: }
076:
077: // takes care of repeating calls to the same object
078: if (a_stack.contains(a_compare)) {
079: return true;
080: }
081: a_stack.push(a_compare);
082:
083: Field fields[] = clazz.getDeclaredFields();
084: for (int i = 0; i < fields.length; i++) {
085: if (storeableField(clazz, fields[i])) {
086: Platform4.setAccessible(fields[i]);
087: try {
088: path = a_path + fields[i].getName() + ":";
089: Object compare = fields[i].get(a_compare);
090: Object with = fields[i].get(a_with);
091: if (compare == null) {
092: if (with != null) {
093: return false;
094: }
095: } else if (with == null) {
096: return false;
097: } else {
098: if (compare.getClass().isArray()) {
099: if (!with.getClass().isArray()) {
100: return false;
101: } else {
102: compare = normalizeNArray(compare);
103: with = normalizeNArray(with);
104: int len = Array.getLength(compare);
105: if (len != Array.getLength(with)) {
106: return false;
107: } else {
108: for (int j = 0; j < len; j++) {
109: Object elementCompare = Array
110: .get(compare, j);
111: Object elementWith = Array.get(
112: with, j);
113: // if (l_persistentArray)
114: if (!isEqual(elementCompare,
115: elementWith, path,
116: a_stack)) {
117: return false;
118: } else if (elementCompare == null) {
119: if (elementWith != null) {
120: return false;
121: }
122: } else if (elementWith == null) {
123: return false;
124: } else {
125: Class elementCompareClass = elementCompare
126: .getClass();
127: if (elementCompareClass != elementWith
128: .getClass()) {
129: return false;
130: }
131: if (hasPublicConstructor(elementCompareClass)) {
132: if (!isEqual(
133: elementCompare,
134: elementWith,
135: path, a_stack)) {
136: return false;
137:
138: }
139: } else if (!elementCompare
140: .equals(elementWith)) {
141: return false;
142: }
143: }
144:
145: }
146:
147: }
148: }
149: } else if (hasPublicConstructor(fields[i]
150: .getType())) {
151: if (!isEqual(compare, with, path, a_stack)) {
152: return false;
153: }
154: } else {
155: if (!compare.equals(with)) {
156: return false;
157: }
158: }
159: }
160: } catch (IllegalAccessException ex) {
161: // probably JDK 1
162: // never mind this field
163: return true;
164: } catch (Exception e) {
165: System.err
166: .println("STCompare failure executing path:"
167: + path);
168: e.printStackTrace();
169: return false;
170: }
171: }
172: }
173: return true;
174: }
175:
176: boolean hasPublicConstructor(Class a_class) {
177: if (a_class != String.class) {
178: try {
179: return a_class.newInstance() != null;
180: } catch (Throwable t) {
181: }
182: }
183: return false;
184: }
185:
186: Object normalizeNArray(Object a_object) {
187: if (Array.getLength(a_object) > 0) {
188: Object first = Array.get(a_object, 0);
189: if (first != null && first.getClass().isArray()) {
190: int dim[] = arrayDimensions(a_object);
191: Object all = new Object[arrayElementCount(dim)];
192: normalizeNArray1(a_object, all, 0, dim, 0);
193: return all;
194: }
195: }
196: return a_object;
197: }
198:
199: int normalizeNArray1(Object a_object, Object a_all, int a_next,
200: int a_dim[], int a_index) {
201: if (a_index == a_dim.length - 1) {
202: for (int i = 0; i < a_dim[a_index]; i++) {
203: Array.set(a_all, a_next++, Array.get(a_object, i));
204: }
205: } else {
206: for (int i = 0; i < a_dim[a_index]; i++) {
207: a_next = normalizeNArray1(Array.get(a_object, i),
208: a_all, a_next, a_dim, a_index + 1);
209: }
210:
211: }
212: return a_next;
213: }
214:
215: int[] arrayDimensions(Object a_object) {
216: int count = 0;
217: for (Class clazz = a_object.getClass(); clazz.isArray(); clazz = clazz
218: .getComponentType()) {
219: count++;
220: }
221: int dim[] = new int[count];
222: for (int i = 0; i < count; i++) {
223: dim[i] = Array.getLength(a_object);
224: a_object = Array.get(a_object, 0);
225: }
226: return dim;
227: }
228:
229: int arrayElementCount(int a_dim[]) {
230: int elements = a_dim[0];
231: for (int i = 1; i < a_dim.length; i++) {
232: elements *= a_dim[i];
233: }
234: return elements;
235: }
236:
237: public boolean storeableField(Class a_class, Field a_field) {
238: return (!Modifier.isStatic(a_field.getModifiers()))
239: && (!Modifier.isTransient(a_field.getModifiers()) & !(a_field
240: .getName().indexOf("$") > -1));
241: }
242:
243: public static boolean isSimple(Class a_class) {
244: for (int i = 0; i < SIMPLE_CLASSES.length; i++) {
245: if (a_class == SIMPLE_CLASSES[i]) {
246: return true;
247: }
248: }
249: return false;
250: }
251:
252: private static final Class[] SIMPLE_CLASSES = { Integer.class,
253: Long.class, Float.class, Boolean.class, Double.class,
254: Byte.class, Character.class, Short.class, String.class,
255: java.util.Date.class };
256:
257: }
|