c8a2773880e14d3ed3c28cb96836b9d586fb3d84
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / ClassDescriptor.java
1 /*
2  * JavaInspect - Utility to visualize java software
3  * Copyright (C) 2013, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU General Public License
7  * as published by the Free Software Foundation.
8  */
9
10 package eu.svjatoslav.inspector.java.structure;
11
12 import java.lang.reflect.Field;
13 import java.lang.reflect.Method;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18
19 /**
20  * Describes single class instance
21  */
22 public class ClassDescriptor implements GraphElement {
23
24         private static final int MAX_REFERECNES_COUNT = 10;
25
26         public final String fullyQualifiedName;
27
28         Map<String, FieldDescriptor> nameToFieldMap = new HashMap<String, FieldDescriptor>();
29
30         public List<MethodDescriptor> methods = new ArrayList<MethodDescriptor>();
31
32         /**
33          * Incoming arrows will have this color.
34          */
35         private String distinctiveReferenceColor;
36
37         private String interfaceColor;
38
39         private String superClassColor;
40
41         boolean isEnum;
42
43         boolean isInterface;
44
45         boolean isArray;
46
47         private final ClassGraph dump;
48
49         List<ClassDescriptor> interfaces = new ArrayList<ClassDescriptor>();
50
51         ClassDescriptor superClass;
52
53         /**
54          * Amount of field and method references pointing to this class.
55          */
56         private int referenceCount = 0;
57
58         public ClassDescriptor(final Class<? extends Object> clazz, final ClassGraph dump) {
59                 this.dump = dump;
60
61                 fullyQualifiedName = clazz.getName();
62                 dump.nameToClassMap.put(fullyQualifiedName, this);
63
64                 isArray = clazz.isArray();
65
66                 if (isArray) {
67                         final Class<?> componentType = clazz.getComponentType();
68                         dump.addClass(componentType);
69                 }
70
71                 // System.out.println("class: " + fullyQualifiedName);
72
73                 isEnum = clazz.isEnum();
74
75                 isInterface = clazz.isInterface();
76
77                 if (!isVisible())
78                         return;
79
80                 indexFields(clazz.getDeclaredFields());
81                 indexFields(clazz.getFields());
82
83                 indexMethods(clazz);
84
85                 for (final Class interfaceClass : clazz.getInterfaces())
86                         interfaces.add(dump.addClass(interfaceClass));
87
88                 superClass = dump.addClass(clazz.getSuperclass());
89         }
90
91         public boolean areReferencesShown() {
92                 return referenceCount <= MAX_REFERECNES_COUNT;
93         }
94
95         public void enlistFieldReferences(final StringBuffer result) {
96                 if (nameToFieldMap.isEmpty())
97                         return;
98
99                 result.append("\n");
100                 result.append("    // field references to other classes\n");
101                 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
102                                 .entrySet())
103                         result.append(entry.getValue().getDot());
104         }
105
106         public void enlistFields(final StringBuffer result) {
107                 if (nameToFieldMap.isEmpty())
108                         return;
109
110                 result.append("\n");
111                 result.append("    // fields:\n");
112
113                 // enlist fields
114                 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
115                                 .entrySet())
116                         result.append(entry.getValue().getEmbeddedDot());
117         }
118
119         public void enlistImplementedInterfaces(final StringBuffer result) {
120                 if (interfaces.isEmpty())
121                         return;
122
123                 result.append("\n");
124                 result.append("    // interfaces implemented by class: "
125                                 + fullyQualifiedName + "\n");
126
127                 for (final ClassDescriptor interfaceDescriptor : interfaces) {
128                         if (!interfaceDescriptor.isVisible())
129                                 continue;
130
131                         result.append("    " + interfaceDescriptor.getGraphId() + " -> "
132                                         + getGraphId() + "[style=\"dotted, tapered\", color=\""
133                                         + interfaceDescriptor.getInterfaceColor()
134                                         + "\", penwidth=20, dir=\"forward\"];\n");
135                 }
136         }
137
138         public void enlistMethodReferences(final StringBuffer result) {
139                 if (methods.isEmpty())
140                         return;
141
142                 result.append("\n");
143                 result.append("    // method references to other classes\n");
144                 for (final MethodDescriptor methodDescriptor : methods)
145                         result.append(methodDescriptor.getDot());
146         }
147
148         public void enlistMethods(final StringBuffer result) {
149                 if (methods.isEmpty())
150                         return;
151
152                 result.append("\n");
153                 result.append("    // methods:\n");
154
155                 // enlist methods
156                 for (final MethodDescriptor methodDescriptor : methods)
157                         result.append(methodDescriptor.getEmbeddedDot());
158         }
159
160         public void enlistSuperClass(final StringBuffer result) {
161                 if (superClass == null)
162                         return;
163
164                 if (!superClass.isVisible())
165                         return;
166
167                 result.append("\n");
168                 result.append("    // super class for: " + fullyQualifiedName + "\n");
169
170                 result.append("    " + superClass.getGraphId() + " -> " + getGraphId()
171                                 + "[style=\"tapered\", color=\""
172                                 + superClass.getSuperClassColor()
173                                 + "\", penwidth=10, dir=\"forward\"];\n");
174         }
175
176         public void generateDotHeader(final StringBuffer result) {
177                 result.append("\n");
178                 result.append("// Class: " + fullyQualifiedName + "\n");
179
180                 result.append("    " + getGraphId() + "[label=<<TABLE "
181                                 + getBackgroundColor() + " BORDER=\"" + getBorderWidth()
182                                 + "\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
183
184                 result.append("\n");
185                 result.append("    // class descriptor header\n");
186                 result.append("    <TR><TD colspan=\"2\" PORT=\"f0\">"
187                                 + "<FONT POINT-SIZE=\"8.0\" >" + getPackageName()
188                                 + "</FONT><br/>" + "<FONT POINT-SIZE=\"25.0\"><B>"
189                                 + getClassName(false) + "</B></FONT>" + "</TD></TR>\n");
190         }
191
192         public List<FieldDescriptor> getAllFields() {
193                 final List<FieldDescriptor> result = new ArrayList<FieldDescriptor>();
194
195                 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
196                                 .entrySet())
197                         result.add(entry.getValue());
198
199                 return result;
200         }
201
202         public String getBackgroundColor() {
203                 String bgColor = "";
204
205                 if (isEnum)
206                         bgColor = "bgcolor=\"navajowhite2\"";
207
208                 if (isInterface)
209                         bgColor = "bgcolor=\"darkslategray1\"";
210
211                 return bgColor;
212         }
213
214         public String getBorderWidth() {
215
216                 if (!areReferencesShown())
217                         return "4";
218                 return "1";
219         }
220
221         public String getClassName(final boolean differentiateArray) {
222
223                 final int i = fullyQualifiedName.lastIndexOf('.');
224
225                 String result = fullyQualifiedName.substring(i + 1);
226
227                 if (isArray)
228                         result = result.substring(0, result.length() - 1);
229
230                 if (differentiateArray)
231                         if (isArray)
232                                 result += " []";
233
234                 return result;
235         }
236
237         public String getColor() {
238                 if (getDistinctiveColor() == null)
239                         setDistinctiveColor(Utils.getNextDarkColor());
240
241                 return getDistinctiveColor();
242         }
243
244         public String getDistinctiveColor() {
245                 return distinctiveReferenceColor;
246         }
247
248         @Override
249         public String getDot() {
250                 if (!isVisible())
251                         return "";
252
253                 if (isArray)
254                         return "";
255
256                 final StringBuffer result = new StringBuffer();
257
258                 generateDotHeader(result);
259
260                 enlistFields(result);
261
262                 enlistMethods(result);
263
264                 result.append("    </TABLE>>, shape=\"none\"];\n");
265
266                 enlistFieldReferences(result);
267
268                 enlistMethodReferences(result);
269
270                 enlistImplementedInterfaces(result);
271
272                 enlistSuperClass(result);
273
274                 return result.toString();
275         }
276
277         @Override
278         public String getEmbeddedDot() {
279                 return null;
280         }
281
282         @Override
283         public String getGraphId() {
284                 final String result = "class_"
285                                 + fullyQualifiedName.replace('.', '_').replace(";", "")
286                                                 .replace("[L", "");
287                 return result;
288         }
289
290         public String getInterfaceColor() {
291                 if (interfaceColor == null)
292                         interfaceColor = Utils.getNextLightColor();
293
294                 return interfaceColor;
295         }
296
297         public String getPackageName() {
298
299                 final int i = fullyQualifiedName.lastIndexOf('.');
300
301                 if (i == -1)
302                         return "";
303
304                 return fullyQualifiedName.substring(0, i).replace("[L", "");
305         }
306
307         // public String getReadableName() {
308         //
309         // // do not print full class name for well known system classes
310         // final String packageName = getPackageName();
311         //
312         // if (packageName.equals("java.util"))
313         // return getClassName();
314         //
315         // if (packageName.equals("java.lang"))
316         // return getClassName();
317         //
318         // return fullyQualifiedName;
319         // }
320
321         public String getSuperClassColor() {
322                 if (superClassColor == null)
323                         superClassColor = Utils.getNextLightColor();
324
325                 return superClassColor;
326         }
327
328         public void indexFields(final Field[] fields) {
329                 for (final Field field : fields) {
330                         if (nameToFieldMap.containsKey(field.getName()))
331                                 continue;
332
333                         final FieldDescriptor fieldDescriptor = new FieldDescriptor(field,
334                                         this, dump);
335
336                 }
337         }
338
339         private void indexMethods(final Class<? extends Object> clazz) {
340                 final Method[] methods = clazz.getMethods();
341
342                 for (final Method method : methods)
343                         new MethodDescriptor(method, this, dump);
344
345         }
346
347         @Override
348         public boolean isVisible() {
349
350                 if (Utils.isSystemDataType(fullyQualifiedName))
351                         return false;
352
353                 if (Utils.isSystemPackage(fullyQualifiedName))
354                         return false;
355
356                 return true;
357         }
358
359         public void registerReference() {
360                 referenceCount++;
361         }
362
363         public void setDistinctiveColor(final String distinctiveColor) {
364                 distinctiveReferenceColor = distinctiveColor;
365         }
366 }