001    /*
002      * mesopotamia @mesopotamia.version@
003     * Multilingual parser and repository. 
004     * Copyright (C) 2005  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://http://www.hammurapi.biz
021     * e-Mail: support@hammurapi.biz
022      */
023    package org.mesopotamia.util;
024    
025    import java.lang.reflect.InvocationTargetException;
026    import java.lang.reflect.Method;
027    import java.lang.reflect.Modifier;
028    import java.util.ArrayList;
029    import java.util.Collection;
030    import java.util.Collections;
031    import java.util.Comparator;
032    import java.util.Iterator;
033    import java.util.List;
034    
035    import javax.swing.table.DefaultTableModel;
036    import javax.swing.table.TableModel;
037    import javax.swing.tree.TreeNode;
038    
039    import org.mesopotamia.LanguageElement;
040    import org.mesopotamia.MesopotamiaNode;
041    import org.mesopotamia.Scan;
042    import org.mesopotamia.SourceUnit;
043    import org.mesopotamia.SyntaxTree;
044    
045    import biz.hammurapi.convert.Converter;
046    import biz.hammurapi.swing.LazyTreeNode;
047    import biz.hammurapi.swing.LazyTreeNodeTableVisualizable;
048    import biz.hammurapi.swing.Visualizable;
049    
050    
051    /**
052     * @author Pavel Vlasov
053     *
054     * @version $Revision: 1.1 $
055     */
056    public class MesopotamiaVisualizer {
057            
058            /**
059             * Invokes method and returns non-null value if the method result shall be mounted to the tree.
060             * @param method
061             * @return true if return value shall be mounted to tree, false if it shall be displayed in the table.
062             * @throws InvocationTargetException 
063             * @throws IllegalAccessException 
064             * @throws  
065             */
066            private Object getNode(Method method, Object obj) throws IllegalAccessException, InvocationTargetException {
067                    if (LanguageElement.class.isAssignableFrom(method.getDeclaringClass())) {
068                            if (((LanguageElement) obj).showInTree(method)) {
069                                    Object returnValue = method.invoke(obj);
070                                    if ((LanguageElement.class.isInstance(returnValue) || List.class.isInstance(returnValue))) {
071                                            return returnValue;
072                                    }
073                            }
074                    } else if (SourceUnit.class.isAssignableFrom(method.getDeclaringClass())) {
075                            if ("getLanguageElements".equals(method.getName()) || "getSyntaxTree".equals(method.getName())) {
076                                    return method.invoke(obj);
077                            }
078                    } else if (Scan.class.isAssignableFrom(method.getDeclaringClass())) {
079                            if ("getSourceUnits".equals(method.getName())) {
080                                    return method.invoke(obj);
081                            }
082                    } else if (SyntaxTree.class.isAssignableFrom(method.getDeclaringClass())) {
083                            if ("getRoots".equals(method.getName())) {
084                                    return method.invoke(obj);
085                            }
086                    } else if (MesopotamiaNode.class.isAssignableFrom(method.getDeclaringClass())) {
087                            if ("getChildren".equals(method.getName())) {
088                                    return method.invoke(obj);
089                            }
090                    }
091                    return null;
092            }
093            
094            public Visualizable convert(final LanguageElement le, final Converter master) {
095                    return new Visualizable() {
096    
097                            public TreeNode toTreeNode(TreeNode parent, String title) {
098                                    return _toTreeNode(parent, title, le, master);
099                            }
100                            
101                    };
102            }
103    
104            public Visualizable convert(final Scan sc, final Converter master) {
105                    return new Visualizable() {
106    
107                            public TreeNode toTreeNode(TreeNode parent, String title) {
108                                    return _toTreeNode(parent, title, sc, master);
109                            }
110                            
111                    };
112            }
113    
114            public Visualizable convert(final SourceUnit su, final Converter master) {
115                    return new Visualizable() {
116    
117                            public TreeNode toTreeNode(TreeNode parent, String title) {
118                                    return _toTreeNode(parent, title, su, master);
119                            }
120                            
121                    };
122            }
123    
124            public Visualizable convert(final SyntaxTree st, final Converter master) {
125                    return new Visualizable() {
126    
127                            public TreeNode toTreeNode(TreeNode parent, String title) {
128                                    return _toTreeNode(parent, title, st, master);
129                            }
130                            
131                    };
132            }
133    
134            public Visualizable convert(final MesopotamiaNode mn, final Converter master) {
135                    return new Visualizable() {
136    
137                            public TreeNode toTreeNode(TreeNode parent, String title) {
138                                    return _toTreeNode(parent, title, mn, master);
139                            }
140                            
141                    };
142            }
143            
144            private TreeNode _toTreeNode(final TreeNode parent, final String title, final Object obj, final Converter master) {
145                    return new LazyTreeNodeTableVisualizable(parent, title) {
146    
147                            public String toString() {
148                                    if (title!=null && title.trim().length()>0) {
149                                            return title;
150                                    }
151                                    
152                                    String ret = obj.getClass().getName();
153                                    int idx = ret.lastIndexOf(".");
154                                    return idx==-1 ? ret : ret.substring(idx+1);
155                            }
156                            
157                            @Override
158                            protected List<TreeNode> loadChildren() {
159                                    List<TreeNode> ret = new ArrayList<TreeNode>();
160                                    if (obj instanceof SyntaxTree) {
161                                            SyntaxTree st = (SyntaxTree) obj;
162                                            Iterator<MesopotamiaNode> it = st.getRoots().iterator();
163                                            while (it.hasNext()) {
164                                                    MesopotamiaNode mn = it.next();
165                                                    Visualizable vs = (Visualizable) master.convert(mn, Visualizable.class, null);
166                                                    ret.add(vs.toTreeNode(this, mn.getTypeName() + " " + (mn.getText()==null ? "" : mn.getText())));
167                                            }
168                                    } else if (obj instanceof MesopotamiaNode) {
169                                            MesopotamiaNode mNode = (MesopotamiaNode) obj;
170                                            Iterator<MesopotamiaNode> it = mNode.getChildren().iterator();
171                                            while (it.hasNext()) {
172                                                    MesopotamiaNode mn = it.next();
173                                                    Visualizable vs = (Visualizable) master.convert(mn, Visualizable.class, null);
174                                                    ret.add(vs.toTreeNode(this, mn.getTypeName() + " " + (mn.getText()==null ? "" : mn.getText())));
175                                            }                                       
176                                    } else {                                
177                                            if (obj instanceof LanguageElement) {
178                                                    MesopotamiaNode mNode = ((LanguageElement) obj).getNode();
179                                                    final Collection<MesopotamiaNode> nChildren = mNode.getChildren();
180                                                    if (!nChildren.isEmpty()) {
181                                                            ret.add(new LazyTreeNode(this, "Syntax tree") {
182    
183                                                                    @Override
184                                                                    protected List<TreeNode> loadChildren() {
185                                                                            List<TreeNode> ret = new ArrayList<TreeNode>();
186                                                                            Iterator<MesopotamiaNode> it = nChildren.iterator();
187                                                                            while (it.hasNext()) {
188                                                                                    MesopotamiaNode mn = it.next();
189                                                                                    Visualizable vs = (Visualizable) master.convert(mn, Visualizable.class, null);
190                                                                                    ret.add(vs.toTreeNode(this, mn.getTypeName() + " " + (mn.getText()==null ? "" : mn.getText())));                                                
191                                                                            }                       
192                                                                            return ret;
193                                                                    }
194                                                                    
195                                                            });
196                                                            
197                                                    }
198                                            }
199                                            
200                                        Method[] methods = obj.getClass().getMethods();
201                                        for (int i=0; i<methods.length; i++) {
202                                            // getXXX() methods. Object and LanguageElement classes are not included.
203                                            if (!(methods[i].getDeclaringClass().equals(Object.class))
204                                                            && methods[i].getName().startsWith("get") 
205                                                            && !Modifier.isStatic(methods[i].getModifiers())
206                                                            && !methods[i].isSynthetic()
207                                                            && methods[i].getParameterTypes().length==0) {
208                                                    try {
209                                                                    Object value=getNode(methods[i], obj);
210                                                                    if (value!=null && (!(value instanceof Collection) || !((Collection) value).isEmpty())) {
211                                                                            Visualizable vs = (Visualizable) master.convert(value, Visualizable.class, null);
212                                                                            ret.add(vs.toTreeNode(this, methods[i].getName().substring("get".length())));
213                                                                    }
214                                                            } catch (Exception e) {
215                                                                    e.printStackTrace();                                                            
216                                                            }
217                                            }                                                                                               
218                                        }
219                                    }
220                                    
221                                    return ret;
222                            }
223    
224                            public TableModel toTable() {
225                                    int rowCount=2;
226                                    DefaultTableModel tm=new DefaultTableModel(rowCount,4);                 
227                                    tm.setColumnIdentifiers(new String[] {"Property", "Declared type", "Runtime type", "Value"});
228                                    
229                                Class<? extends Object> beanClass=obj.getClass();
230                                
231                                    tm.setValueAt("this", 0, 0);
232                                    tm.setValueAt(beanClass.getName(), 0, 2);
233                                    tm.setValueAt(obj, 0, 3);
234                                    
235                                    tm.setValueAt("Hash code", 1, 0);
236                                    tm.setValueAt("int", 1, 1);
237                                    tm.setValueAt("int", 1, 2);
238                                    tm.setValueAt(Integer.toString(obj.hashCode(), Character.MAX_RADIX), 1, 3);
239                                    
240                                Method[] methods = beanClass.getMethods();
241                                List<Method> ml = new ArrayList<Method>();
242                                for (int i=0; i<methods.length; i++) {
243                                    ml.add(methods[i]);
244                                }
245                                
246                                Collections.sort(ml, new Comparator<Method>() {
247    
248                                            public int compare(Method m0, Method m1) {
249                                                    return m0.getName().compareTo(m1.getName());
250                                            }
251                                    
252                                });
253                                
254                                Iterator<Method> it = ml.iterator();
255                                while (it.hasNext()) {
256                                    Method method = it.next();
257                                    // getXXX() methods. Object.getClass() is not included.
258                                    if (!(method.getDeclaringClass().equals(Object.class)) 
259                                                    && method.getName().startsWith("get") 
260                                                    && method.getParameterTypes().length==0) {
261                                            try {
262                                                    if (getNode(method, obj)==null) {
263                                                                    Object value=method.invoke(obj);
264                                                                    if (value!=null) {
265                                                                            tm.setRowCount(++rowCount);
266                                                                            int idx = rowCount-1;
267                                                                            tm.setValueAt(method.getName().substring(3), idx, 0);
268                                                                            tm.setValueAt(method.getReturnType().getName(), idx, 1);
269                                                                            tm.setValueAt(value.getClass().getName(), idx, 2);
270                                                                            tm.setValueAt(value, idx, 3);
271                                                                    }
272                                                    }
273                                                    } catch (Exception e) {
274                                                            e.printStackTrace();                                                            
275                                                    }
276                                    }                                                                                               
277                                }
278                                                        
279                                    return tm;
280                            }
281                            
282                    };
283                    
284            }
285    }