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.tools;
022:
023: import java.io.*;
024: import java.lang.reflect.*;
025:
026: import com.db4o.*;
027: import com.db4o.ext.*;
028: import com.db4o.foundation.*;
029: import com.db4o.internal.*;
030:
031: /**
032: * Logger class to log and analyse objects in RAM.
033: * <br><br><b>This class is not part of db4o.jar!</b><br>
034: * It is delivered as sourcecode in the
035: * path ../com/db4o/tools/<br><br>
036: */
037: public class Logger {
038:
039: private static final int MAXIMUM_OBJECTS = 20;
040:
041: /**
042: * opens a database file and logs the content of a class to standard out.
043: * @param args expects [database filename] [fully qualified classname]
044: */
045: public static void main(String[] args) {
046: if (args == null || args.length == 0) {
047: System.out
048: .println("Usage: java com.db4o.tools.Logger <database filename> <class>");
049: } else {
050: if (!new File(args[0]).exists()) {
051: System.out.println("A database file with the name '"
052: + args[0] + "' does not exist.");
053: } else {
054: Db4o.configure().messageLevel(-1);
055: ExtObjectContainer con = null;
056: try {
057: ObjectContainer c = Db4o.openFile(args[0]);
058: if (c == null) {
059: throw new RuntimeException();
060: }
061: con = c.ext();
062: } catch (Exception e) {
063: System.out.println("The database file '" + args[0]
064: + "' could not be opened.");
065: return;
066: }
067:
068: if (args.length > 1) {
069: StoredClass sc = con.storedClass(args[1]);
070: if (sc == null) {
071: System.out
072: .println("There is no stored class with the name '"
073: + args[1] + "'.");
074: } else {
075: long[] ids = sc.getIDs();
076: for (int i = 0; i < ids.length; i++) {
077: if (i > MAXIMUM_OBJECTS) {
078: break;
079: }
080: Object obj = con.getByID(ids[i]);
081: con.activate(obj, Integer.MAX_VALUE);
082: log(con, obj);
083: }
084: msgCount(ids.length);
085: }
086: } else {
087: ObjectSet set = con.get(null);
088: int i = 0;
089: while (set.hasNext()) {
090: Object obj = set.next();
091: con.activate(obj, Integer.MAX_VALUE);
092: log(con, obj);
093:
094: if (++i > MAXIMUM_OBJECTS) {
095: break;
096: }
097: }
098: msgCount(set.size());
099: }
100: con.close();
101:
102: }
103:
104: }
105: }
106:
107: /**
108: * logs the structure of an object.
109: * @param container the {@link ObjectContainer} to be used, or null
110: * to log any object.
111: * @param obj the object to be analysed.
112: */
113: public static void log(ObjectContainer container, Object obj) {
114: if (obj == null) {
115: log("[NULL]");
116: } else {
117: log(obj.getClass().getName());
118: log(container, obj, 0, new Collection4());
119: }
120: }
121:
122: /**
123: * logs the structure of an object.
124: * @param obj the object to be analysed.
125: */
126: public static void log(Object obj) {
127: log(null, obj);
128: }
129:
130: /**
131: * logs all objects in the passed ObjectContainer.
132: * @param container the {@link ObjectContainer} to be used.
133: */
134: public static void logAll(ObjectContainer container) {
135: ObjectSet set = container.get(null);
136: while (set.hasNext()) {
137: log(container, set.next());
138: }
139: }
140:
141: /**
142: * redirects output to a different PrintStream.
143: * @param ps the Printstream to be used.
144: */
145: public static void setOut(java.io.PrintStream ps) {
146: out = ps;
147: }
148:
149: /**
150: * limits logging to a maximum depth.
151: * @param depth the maximum depth.
152: */
153: public static void setMaximumDepth(int depth) {
154: maximumDepth = depth;
155: }
156:
157: private static void msgCount(int count) {
158: System.out.println("\n\nLog complete.\nObjects: " + count);
159: if (count > MAXIMUM_OBJECTS) {
160: System.out.println("Displayed due to setting of "
161: + Logger.class.getName() + "#MAXIMUM_OBJECTS: "
162: + MAXIMUM_OBJECTS);
163: }
164: }
165:
166: private static void log(ObjectContainer a_container,
167: Object a_object, int a_depth, Collection4 a_list) {
168: if (a_list.contains(a_object) || a_depth > maximumDepth) {
169: return;
170: }
171: Class clazz = a_object.getClass();
172: for (int i = 0; i < IGNORE.length; i++) {
173: if (clazz.isAssignableFrom(IGNORE[i])) {
174: return;
175: }
176: }
177: if (Platform4.isSimple(clazz)) {
178: log(a_depth + 1, a_object.getClass().getName(), a_object
179: .toString());
180: return;
181: }
182:
183: a_list.add(a_object);
184:
185: Class[] classes = getClassHierarchy(a_object);
186:
187: String spaces = "";
188: for (int i = classes.length - 1; i >= 0; i--) {
189: spaces = spaces + sp;
190:
191: String className = spaces;
192: int pos = classes[i].getName().lastIndexOf(".");
193: if (pos > 0) {
194: className += classes[i].getName().substring(pos);
195: } else {
196: className += classes[i].getName();
197: }
198:
199: if (classes[i] == java.util.Date.class) {
200: String fieldName = className + ".getTime";
201: Object obj = new Long(((java.util.Date) a_object)
202: .getTime());
203: log(a_container, obj, fieldName, a_depth + 1, -1,
204: a_list);
205:
206: } else {
207: Field[] fields = classes[i].getDeclaredFields();
208: for (int j = 0; j < fields.length; j++) {
209: Platform4.setAccessible(fields[j]);
210: String fieldName = className + "."
211: + fields[j].getName();
212: try {
213: Object obj = fields[j].get(a_object);
214: if (obj.getClass().isArray()) {
215: obj = normalizeNArray(obj);
216: int len = Array.getLength(obj);
217: for (int k = 0; k < len; k++) {
218: Object element = Array.get(obj, k);
219: log(a_container, element, fieldName,
220: a_depth + 1, k, a_list);
221: }
222: } else {
223: log(a_container, obj, fieldName,
224: a_depth + 1, -1, a_list);
225: }
226: } catch (Exception e) {
227: }
228: }
229: }
230: }
231: }
232:
233: private static void log(ObjectContainer a_container,
234: Object a_object, String a_fieldName, int a_depth,
235: int a_arrayElement, Collection4 a_list) {
236: if (a_depth > maximumDepth) {
237: return;
238: }
239: String fieldName = (a_arrayElement > -1) ? a_fieldName + sp
240: + sp + a_arrayElement : a_fieldName;
241: if (a_object != null) {
242: if ((a_container == null)
243: || a_container.ext().isStored(a_object)) {
244: if (a_container == null
245: || a_container.ext().isActive(a_object)) {
246: log(a_depth, fieldName, "");
247: Class clazz = a_object.getClass();
248: boolean found = false;
249: if (Platform4.isSimple(clazz)) {
250: log(a_depth + 1, a_object.getClass().getName(),
251: a_object.toString());
252: found = true;
253: }
254: if (!found) {
255: log(a_container, a_object, a_depth, a_list);
256: }
257: } else {
258: log(a_depth, fieldName, "DEACTIVATED "
259: + a_object.getClass().getName());
260: }
261: return;
262: }
263: log(a_depth, fieldName, a_object.toString());
264: } else {
265: log(a_depth, fieldName, "[NULL]");
266: }
267: }
268:
269: private static void log(String a_msg) {
270: if (!silent) {
271: out.println(a_msg);
272: }
273: }
274:
275: private static void log(int indent, String a_property,
276: String a_value) {
277: for (int i = 0; i < indent; i++) {
278: a_property = sp + sp + a_property;
279: }
280: log(a_property, a_value);
281: }
282:
283: private static void log(String a_property, String a_value) {
284: if (a_value == null)
285: a_value = "[NULL]";
286: log(a_property + ": " + a_value);
287: }
288:
289: private static Class[] getClassHierarchy(Object a_object) {
290: Class[] classes = new Class[] { a_object.getClass() };
291: return getClassHierarchy(classes);
292: }
293:
294: private static Class[] getClassHierarchy(Class[] a_classes) {
295: Class clazz = a_classes[a_classes.length - 1].getSuperclass();
296: if (clazz.equals(Object.class)) {
297: return a_classes;
298: }
299: Class[] classes = new Class[a_classes.length + 1];
300: System.arraycopy(a_classes, 0, classes, 0, a_classes.length);
301: classes[a_classes.length] = clazz;
302: return getClassHierarchy(classes);
303: }
304:
305: private static Object normalizeNArray(Object a_object) {
306: if (Array.getLength(a_object) > 0) {
307: Object first = Array.get(a_object, 0);
308: if (first != null && first.getClass().isArray()) {
309: int dim[] = arrayDimensions(a_object);
310: Object all = new Object[arrayElementCount(dim)];
311: normalizeNArray1(a_object, all, 0, dim, 0);
312: return all;
313: }
314: }
315: return a_object;
316: }
317:
318: private static int normalizeNArray1(Object a_object, Object a_all,
319: int a_next, int a_dim[], int a_index) {
320: if (a_index == a_dim.length - 1) {
321: for (int i = 0; i < a_dim[a_index]; i++) {
322: Array.set(a_all, a_next++, Array.get(a_object, i));
323: }
324: } else {
325: for (int i = 0; i < a_dim[a_index]; i++) {
326: a_next = normalizeNArray1(Array.get(a_object, i),
327: a_all, a_next, a_dim, a_index + 1);
328: }
329:
330: }
331: return a_next;
332: }
333:
334: private static int[] arrayDimensions(Object a_object) {
335: int count = 0;
336: for (Class clazz = a_object.getClass(); clazz.isArray(); clazz = clazz
337: .getComponentType()) {
338: count++;
339: }
340: int dim[] = new int[count];
341: for (int i = 0; i < count; i++) {
342: dim[i] = Array.getLength(a_object);
343: a_object = Array.get(a_object, 0);
344: }
345: return dim;
346: }
347:
348: private static int arrayElementCount(int a_dim[]) {
349: int elements = a_dim[0];
350: for (int i = 1; i < a_dim.length; i++) {
351: elements *= a_dim[i];
352: }
353: return elements;
354: }
355:
356: private static final Class[] IGNORE = { Class.class };
357:
358: private static int maximumDepth = Integer.MAX_VALUE;
359: private static java.io.PrintStream out = System.out;
360: private static String sp = " ";
361: private static boolean silent;
362:
363: /**
364: * static use only
365: */
366: private Logger() {
367: }
368: }
|