001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.text;
005:
006: import java.io.PrintWriter;
007: import java.util.ArrayList;
008: import java.util.Collection;
009: import java.util.IdentityHashMap;
010: import java.util.Iterator;
011: import java.util.Map;
012:
013: public class PrettyPrinter {
014:
015: private static final String INDENT = "--> ";
016:
017: private final StringBuffer prefix;
018: private final PrintWriter out;
019: private final IdentityHashMap visited;
020:
021: private final PrintPolicy defaultPolicy = new BasicPrintPolicy();
022: private final Collection policies;
023:
024: private boolean autoflush = true;
025:
026: public PrettyPrinter(PrintWriter out) {
027: this (INDENT, out, new IdentityHashMap());
028: }
029:
030: private PrettyPrinter(String prefix, PrintWriter out,
031: IdentityHashMap visited) {
032: this .prefix = new StringBuffer(prefix);
033: this .out = out;
034: this .visited = visited;
035: this .policies = initPolicies();
036: }
037:
038: public synchronized void autoflush(boolean b) {
039: this .autoflush = b;
040: }
041:
042: public synchronized boolean autoflush() {
043: return this .autoflush;
044: }
045:
046: /**
047: * Returns true if the object has been visited before or if the object is null. Otherwise, it accounts for the visited
048: * object and returns false.
049: */
050: private boolean accountFor(Object o) {
051: if (o == null)
052: return false;
053: synchronized (visited) {
054: if (visited.containsKey(o)) {
055: return true;
056: } else {
057: visited.put(o, "");
058: return false;
059: }
060: }
061: }
062:
063: public PrettyPrinter print(Object o) {
064: this .out.print(o);
065: if (autoflush())
066: this .out.flush();
067: return this ;
068: }
069:
070: public PrettyPrinter println(Object o) {
071: this .out.println(o);
072: if (autoflush())
073: this .out.flush();
074: return this ;
075: }
076:
077: public PrettyPrinter println() {
078: this .out.println();
079: if (autoflush())
080: this .out.flush();
081: return this ;
082: }
083:
084: public PrettyPrinter indent() {
085: return print(prefix);
086: }
087:
088: public PrettyPrinter duplicateAndIndent() {
089: PrettyPrinter rv = duplicate();
090: rv.indentPrefix();
091: return rv;
092: }
093:
094: private void indentPrefix() {
095: if (prefix.indexOf("+") > -1)
096: prefix.replace(prefix.indexOf("+"),
097: prefix.indexOf("+") + 1, "|");
098: prefix.insert(prefix.indexOf("-->"), " +");
099: }
100:
101: private PrettyPrinter duplicate() {
102: return new PrettyPrinter(prefix.toString(), out, this .visited);
103: }
104:
105: public PrettyPrinter visit(Object o) {
106: if (accountFor(o)) {
107: print("ALREADY VISITED: " + o);
108: return this ;
109: } else {
110: return basicVisit(o);
111: }
112: }
113:
114: private PrettyPrinter basicVisit(Object o) {
115: PrintPolicy policy = findPolicyFor(o);
116: return policy.visit(this , o);
117: }
118:
119: private PrintPolicy findPolicyFor(Object o) {
120: if (o == null)
121: return defaultPolicy;
122: for (Iterator i = policies.iterator(); i.hasNext();) {
123: PrintPolicy policy = (PrintPolicy) i.next();
124: if (policy.accepts(o)) {
125: return policy;
126: }
127: }
128: return defaultPolicy;
129: }
130:
131: /**
132: * Creates a policy path. Each policy is searched in order.
133: */
134: private Collection initPolicies() {
135: Collection rv = new ArrayList();
136: rv.add(new PrettyPrintablePrintPolicy());
137: rv.add(new ShallowMapPrintPolicy());
138: rv.add(new ShallowCollectionPrintPolicy());
139: rv.add(defaultPolicy);
140: return rv;
141: }
142:
143: private static interface PrintPolicy {
144: public PrettyPrinter visit(PrettyPrinter pp, Object o);
145:
146: public boolean accepts(Object o);
147: }
148:
149: private static class PrettyPrintablePrintPolicy implements
150: PrintPolicy {
151:
152: public PrettyPrinter visit(PrettyPrinter pp, Object o) {
153: return ((PrettyPrintable) o).prettyPrint(pp);
154: }
155:
156: public boolean accepts(Object o) {
157: return o != null && o instanceof PrettyPrintable;
158: }
159:
160: }
161:
162: private static class ShallowMapPrintPolicy implements PrintPolicy {
163:
164: public PrettyPrinter visit(PrettyPrinter pp, Object o) {
165: return pp.print(o.getClass().getName()).print(".size()=")
166: .print(((Map) o).size() + "");
167: }
168:
169: public boolean accepts(Object o) {
170: return o != null && o instanceof Map;
171: }
172:
173: }
174:
175: private static class ShallowCollectionPrintPolicy implements
176: PrintPolicy {
177:
178: public PrettyPrinter visit(PrettyPrinter pp, Object o) {
179: return pp.print(o.getClass().getName()).print(".size()=")
180: .print(((Collection) o).size() + "");
181: }
182:
183: public boolean accepts(Object o) {
184: return o != null && o instanceof Collection;
185: }
186:
187: }
188:
189: private static class BasicPrintPolicy implements PrintPolicy {
190:
191: public PrettyPrinter visit(PrettyPrinter pp, Object o) {
192: return pp.print(o);
193: }
194:
195: public boolean accepts(Object o) {
196: return true;
197: }
198:
199: }
200: }
|