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.swing;
024:
025: import java.io.IOException;
026: import java.lang.reflect.InvocationTargetException;
027: import java.lang.reflect.Method;
028: import java.util.ArrayList;
029: import java.util.Collection;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.Stack;
034:
035: import javax.swing.table.DefaultTableModel;
036: import javax.swing.table.TableModel;
037: import javax.swing.tree.DefaultMutableTreeNode;
038: import javax.swing.tree.MutableTreeNode;
039:
040: import biz.hammurapi.RuntimeException;
041: import biz.hammurapi.config.ConfigurationException;
042: import biz.hammurapi.config.DomConfigFactory;
043: import biz.hammurapi.util.ClassHierarchyVisitable;
044: import biz.hammurapi.util.Visitor;
045:
046: /**
047: * @author Pavel Vlasov
048: *
049: * @version $Revision: 1.2 $
050: */
051: public class CompositeVisualizer {
052:
053: public interface Member {
054: /**
055: * Callback method
056: * @param owner
057: */
058: void setOwner(CompositeVisualizer owner);
059: }
060:
061: private Collection visualizers = new ArrayList();
062:
063: /**
064: * Visualizer which to delegate visualization to
065: * if this visualizer doesn't containt appropriate
066: * means to visualize given object.
067: */
068: protected CompositeVisualizer upInStack;
069:
070: /**
071: * Visualizer to delegate requests for visualization from members.
072: */
073: protected CompositeVisualizer downInStack;
074:
075: /**
076: * For use by members.
077: * @return CompositeVisualizer at stack's head to delegate requests
078: * from members to.
079: */
080: public CompositeVisualizer getStackHead() {
081: return (downInStack == null || downInStack == this ) ? this
082: : downInStack.getStackHead();
083: }
084:
085: /**
086: * Creates visualizer prepopulated with standard visualizers
087: * loaded from com/pavelvlasov/swing/CompositeVisualizer.xml resource.
088: */
089: public CompositeVisualizer() {
090: Iterator it = standardVisualizers.iterator();
091: while (it.hasNext()) {
092: addVisualizer(it.next());
093: }
094: }
095:
096: /**
097: * Creates visualizer populated with given collection of visualizers
098: * @param visualizers
099: */
100: public CompositeVisualizer(Collection visualizers) {
101: Iterator it = visualizers.iterator();
102: while (it.hasNext()) {
103: addVisualizer(it.next());
104: }
105: }
106:
107: private interface Visualizer {
108: Class getSourceClass();
109:
110: Visualizable toVisualizable(Object o);
111: }
112:
113: public void addVisualizer(final Object v) {
114: if (v instanceof Member) {
115: ((Member) v).setOwner(this );
116: }
117:
118: final Class clazz = v.getClass();
119: Method[] ma = clazz.getMethods();
120:
121: for (int i = 0; i < ma.length; i++) {
122: if ("toVisualizable".equals(ma[i].getName())
123: && Visualizable.class.isAssignableFrom(ma[i]
124: .getReturnType())
125: && ma[i].getParameterTypes().length == 1) {
126:
127: final Method m = ma[i];
128: visualizers.add(new Visualizer() {
129:
130: public Class getSourceClass() {
131: return m.getParameterTypes()[0];
132: }
133:
134: public Visualizable toVisualizable(Object o) {
135: try {
136: return (Visualizable) m.invoke(v,
137: new Object[] { o });
138: } catch (IllegalAccessException e) {
139: throw new RuntimeException(e);
140: } catch (InvocationTargetException e) {
141: throw new RuntimeException(e);
142: }
143: }
144: });
145:
146: }
147: }
148: }
149:
150: private Map visualizerMap = new HashMap();
151:
152: private static final Visualizable nullVisualizible = new Visualizable() {
153:
154: public MutableTreeNode toTree(final String title) {
155: DefaultMutableTreeNode ret = new DefaultMutableTreeNode() {
156: public String toString() {
157: return title + " - null";
158: }
159: };
160: return ret;
161: }
162:
163: public TableModel toTable() {
164: DefaultTableModel ret = new DefaultTableModel(1, 2);
165: ret.setValueAt("Value", 0, 0);
166: ret.setValueAt("(null)", 0, 1);
167: ret
168: .setColumnIdentifiers(new String[] { "Property",
169: "Value" });
170: return null;
171: }
172:
173: };
174:
175: public Visualizable toVisualizable(Object object) {
176: if (object == null) {
177: return nullVisualizible;
178: }
179:
180: if (object instanceof Visualizable) {
181: return (Visualizable) object;
182: }
183:
184: Visualizer visualizer;
185: synchronized (visualizerMap) {
186: visualizer = (Visualizer) visualizerMap.get(object
187: .getClass().getName());
188: if (visualizer == null) {
189: int affinity = Integer.MAX_VALUE;
190: Iterator it = visualizers.iterator();
191: while (it.hasNext()) {
192: final Visualizer v = (Visualizer) it.next();
193: if (v.getSourceClass().isInstance(object)
194: && v.getSourceClass().isArray() == object
195: .getClass().isArray()) {
196: final int[] caffinity = { 0 };
197: new ClassHierarchyVisitable(object.getClass())
198: .accept(new Visitor() {
199:
200: public boolean visit(Object target) {
201: if (target.equals(v
202: .getSourceClass())) {
203: return false;
204: }
205:
206: caffinity[0]++;
207: return true;
208: }
209:
210: });
211:
212: // System.out.println(object.getClass()+" - "+ds.getSourceClass()+" : "+caffinity[0]);
213:
214: if (visualizer == null
215: || caffinity[0] < affinity) {
216: visualizer = v;
217: affinity = caffinity[0];
218: }
219: }
220: }
221:
222: if (visualizer != null) {
223: visualizerMap.put(object.getClass().getName(),
224: visualizer);
225: }
226: }
227: }
228:
229: if (visualizer == null) {
230: return upInStack == null ? null : upInStack
231: .toVisualizable(object);
232: }
233:
234: return visualizer.toVisualizable(object);
235: }
236:
237: private static CompositeVisualizer defaultInstance;
238:
239: private static Collection standardVisualizers;
240:
241: static {
242: try {
243: DomConfigFactory factory = new DomConfigFactory();
244: standardVisualizers = (Collection) factory
245: .create(
246: CompositeVisualizer.class
247: .getResourceAsStream("CompositeVisualizer.xml"),
248: null);
249: } catch (ConfigurationException e) {
250: throw new ExceptionInInitializerError(e);
251: } catch (IOException e) {
252: throw new ExceptionInInitializerError(e);
253: }
254: defaultInstance = new CompositeVisualizer();
255: }
256:
257: private static ThreadLocal threadVisualizerTL = new ThreadLocal() {
258: protected Object initialValue() {
259: return new Stack();
260: }
261: };
262:
263: public static CompositeVisualizer getThreadInstance() {
264: Stack stack = (Stack) threadVisualizerTL.get();
265:
266: if (stack.isEmpty()) {
267: return defaultInstance;
268: }
269:
270: return (CompositeVisualizer) stack.peek();
271: }
272:
273: public static void pushThreadVisualizer(
274: CompositeVisualizer threadVisualizer) {
275: if (threadVisualizer != null) {
276: CompositeVisualizer cti = getThreadInstance();
277: if (cti != threadVisualizer) {
278: threadVisualizer.upInStack = cti;
279: cti.downInStack = threadVisualizer;
280: ((Stack) threadVisualizerTL.get())
281: .push(threadVisualizer);
282: }
283: }
284: }
285:
286: public static CompositeVisualizer popThreadVisualizer() {
287: Stack stack = (Stack) threadVisualizerTL.get();
288: if (stack.isEmpty()) {
289: return null;
290: }
291:
292: CompositeVisualizer ret = (CompositeVisualizer) stack.pop();
293: if (ret.upInStack != null) {
294: ret.upInStack.downInStack = null;
295: ret.upInStack = null;
296: }
297: return ret;
298: }
299:
300: }
|