• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package ohos.devtools.views.layout.chartview.memory.nativehook;
17 
18 import com.intellij.ui.components.JBPanel;
19 import com.intellij.ui.treeStructure.treetable.TreeColumnInfo;
20 import com.intellij.util.ui.ColumnInfo;
21 import ohos.devtools.datasources.utils.profilerlog.ProfilerLogManager;
22 import ohos.devtools.services.memory.nativebean.HookDataBean;
23 import ohos.devtools.services.memory.nativebean.NativeFrame;
24 import ohos.devtools.services.memory.nativebean.NativeInstanceObject;
25 import ohos.devtools.services.memory.nativeservice.NativeDataExternalInterface;
26 import ohos.devtools.views.common.treetable.TreeTableColumn;
27 import org.apache.commons.collections.map.MultiValueMap;
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 
31 import javax.swing.SortOrder;
32 import javax.swing.event.TreeExpansionEvent;
33 import javax.swing.event.TreeWillExpandListener;
34 import javax.swing.tree.DefaultMutableTreeNode;
35 import javax.swing.tree.ExpandVetoException;
36 import javax.swing.tree.TreeNode;
37 import java.awt.BorderLayout;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.Enumeration;
42 import java.util.Iterator;
43 import java.util.Objects;
44 import java.util.Set;
45 
46 import static javax.swing.tree.DefaultMutableTreeNode.EMPTY_ENUMERATION;
47 import static ohos.devtools.views.layout.chartview.memory.nativehook.NativeHookTreeTableRenderer.HookDataBeanEnum.CALLSTACK_ENUM;
48 import static ohos.devtools.views.layout.chartview.memory.nativehook.NativeHookTreeTableRenderer.HookDataBeanEnum.HEAP_ENUM;
49 import static ohos.devtools.views.layout.chartview.memory.nativehook.NativeHookTreeTableRenderer.HookDataBeanEnum.MALLOC_ENUM;
50 
51 /**
52  * NativeHookTreeTablePanel
53  *
54  * @since 2021/10/25
55  */
56 public class NativeHookTreeTablePanel extends JBPanel {
57     private static final Logger LOGGER = LogManager.getLogger(NativeHookTreeTablePanel.class);
58 
59     /**
60      * columns
61      */
62     public final ColumnInfo[] columns = new ColumnInfo[] {new TreeColumnInfo("Allocation function"),
63         new TreeTableColumn<>("ModuleName", HookDataBean.class) {
64             @Override
65             public String getColumnValue(HookDataBean nodeData) {
66                 return nodeData.getHookModuleName();
67             }
68         }, new TreeTableColumn<>("Allocations", HookDataBean.class) {
69         @Override
70         public String getColumnValue(HookDataBean nodeData) {
71             return String.valueOf(nodeData.getHookAllocationCount());
72         }
73     }, new TreeTableColumn<>("Deallocations", HookDataBean.class) {
74         @Override
75         public String getColumnValue(HookDataBean nodeData) {
76             return String.valueOf(nodeData.getHookDeAllocationCount());
77         }
78     }, new TreeTableColumn<>("Allocations Size", HookDataBean.class) {
79         @Override
80         public String getColumnValue(HookDataBean nodeData) {
81             return String.valueOf(nodeData.getHookAllocationMemorySize());
82         }
83     }, new TreeTableColumn<>("Deallocations Size", HookDataBean.class) {
84         @Override
85         public String getColumnValue(HookDataBean nodeData) {
86             return String.valueOf(nodeData.getHookDeAllocationMemorySize());
87         }
88     }, new TreeTableColumn<>("Total Count", HookDataBean.class) {
89         @Override
90         public String getColumnValue(HookDataBean nodeData) {
91             return String.valueOf(nodeData.getTotalCount());
92         }
93     }, new TreeTableColumn<>("Remainning Size", HookDataBean.class) {
94         @Override
95         public String getColumnValue(HookDataBean nodeData) {
96             return String.valueOf(nodeData.getReaminSize());
97         }
98     }};
99 
100     private NativeDataExternalInterface dataInterface;
101     private DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
102     private NativeHookTreeTable treeTable;
103     private MultiValueMap nativeData;
104     private int currentSortKey = 1;
105     private SortOrder currentOrder = SortOrder.DESCENDING;
106     private NativeHookTreeTableModel tableModelOnColumns;
107     private String searchText = "";
108 
109     /**
110      * NativeHookTreeTablePanel
111      *
112      * @param sessionId sessionId
113      * @param dataInterface dataInterface
114      */
NativeHookTreeTablePanel(long sessionId, NativeDataExternalInterface dataInterface)115     public NativeHookTreeTablePanel(long sessionId, NativeDataExternalInterface dataInterface) {
116         this.dataInterface = dataInterface;
117         setLayout(new BorderLayout());
118         root = arrangeAllocationMethodDataNode();
119         createTreeTable(root);
120         add(treeTable, BorderLayout.CENTER);
121     }
122 
123     /**
124      * arrange CallStackDataNode
125      *
126      * @return DefaultMutableTreeNode
127      */
arrangeCallStackDataNode()128     public DefaultMutableTreeNode arrangeCallStackDataNode() {
129         if (ProfilerLogManager.isInfoEnabled()) {
130             LOGGER.info("arrangeCallStackDataNode");
131         }
132         if (nativeData == null || nativeData.size() == 0) {
133             nativeData = dataInterface.getNativeInstanceMap();
134         }
135         DefaultMutableTreeNode appNode = new DefaultMutableTreeNode();
136         Set<String> endCallNamesSet = nativeData.keySet();
137         int totalAllocations = 0;
138         int totalDeallocations = 0;
139         long totalAllocationsSize = 0L;
140         long totalDeallocationsSize = 0L;
141         for (String endCallName : endCallNamesSet) {
142             Collection collections = nativeData.getCollection(endCallName);
143             Iterator iterator = collections.iterator();
144             while (iterator.hasNext()) {
145                 NativeInstanceObject nativeInstance = null;
146                 Object nextObject = iterator.next();
147                 if (nextObject instanceof NativeInstanceObject) {
148                     nativeInstance = (NativeInstanceObject) nextObject;
149                     totalAllocations += nativeInstance.getInstanceCount();
150                     totalAllocationsSize += nativeInstance.getAllowSize();
151                     if (nativeInstance.isDeAllocated()) {
152                         totalDeallocations += nativeInstance.getInstanceCount();
153                         totalDeallocationsSize += nativeInstance.getAllowSize();
154                     }
155                     createTreeNode(nativeInstance, appNode);
156                 }
157             }
158         }
159         HookDataBean dataNode = new HookDataBean();
160         dataNode.setHookMethodName("Native heap");
161         dataNode.setHookAllocationCount(totalAllocations);
162         dataNode.setHookDeAllocationCount(totalDeallocations);
163         dataNode.setHookAllocationMemorySize(totalAllocationsSize);
164         dataNode.setHookDeAllocationMemorySize(totalDeallocationsSize);
165         dataNode.setBeanEnum(HEAP_ENUM);
166         appNode.setUserObject(dataNode);
167         return appNode;
168     }
169 
createTreeNode(NativeInstanceObject nativeInstance, DefaultMutableTreeNode root)170     private void createTreeNode(NativeInstanceObject nativeInstance, DefaultMutableTreeNode root) {
171         if (ProfilerLogManager.isInfoEnabled()) {
172             LOGGER.info("createTreeNode");
173         }
174         Enumeration<TreeNode> children = root.children();
175         ArrayList<NativeFrame> nativeFrames = nativeInstance.getNativeFrames();
176         ArrayList<NativeFrame> dest = new ArrayList<>(nativeFrames);
177         Collections.reverse(dest);
178         if (children == EMPTY_ENUMERATION) {
179             DefaultMutableTreeNode nodeZero = crateNode(nativeInstance, dest, 0);
180             root.add(nodeZero);
181             HookDataBean hookDataBean;
182             Object userObjectNew = nodeZero.getUserObject();
183             if (userObjectNew instanceof HookDataBean) {
184                 hookDataBean = (HookDataBean) userObjectNew;
185                 HookDataBean rootNode;
186                 Object object = root.getUserObject();
187                 if (Objects.isNull(object)) {
188                     rootNode = new HookDataBean();
189                     rootNode.setHookAllocationCount(hookDataBean.getHookAllocationCount());
190                     rootNode.setHookAllocationMemorySize(hookDataBean.getHookAllocationMemorySize());
191                     rootNode.setHookDeAllocationCount(hookDataBean.getHookDeAllocationCount());
192                     rootNode.setHookDeAllocationMemorySize(hookDataBean.getHookDeAllocationMemorySize());
193                     root.setUserObject(rootNode);
194                 }
195             }
196         } else {
197             insertNodeInTreeNode(nativeInstance, dest, root, 0);
198         }
199     }
200 
insertNodeInTreeNode(NativeInstanceObject nativeInstance, ArrayList<NativeFrame> nativeFrames, DefaultMutableTreeNode parentNode, int startIndex)201     private void insertNodeInTreeNode(NativeInstanceObject nativeInstance, ArrayList<NativeFrame> nativeFrames,
202         DefaultMutableTreeNode parentNode, int startIndex) {
203         if (ProfilerLogManager.isInfoEnabled()) {
204             LOGGER.info("insertNodeInTreeNode");
205         }
206         Enumeration<TreeNode> children = parentNode.children();
207         boolean insert = false;
208         while (children.hasMoreElements()) {
209             DefaultMutableTreeNode child = null;
210             Object elementObject = children.nextElement();
211             if (elementObject instanceof DefaultMutableTreeNode) {
212                 child = (DefaultMutableTreeNode) elementObject;
213                 HookDataBean userObject = null;
214                 Object object = child.getUserObject();
215                 if (object instanceof HookDataBean) {
216                     userObject = (HookDataBean) object;
217                 }
218                 if (userObject != null && userObject.getHookMethodName()
219                     .equals(nativeFrames.get(startIndex).getFunctionName().trim())) {
220                     int index = startIndex + 1;
221                     if (userObject.getBeanEnum() == MALLOC_ENUM && nativeFrames.size() == index) {
222                         HookDataBean newUserObject = new HookDataBean();
223                         newUserObject.setBeanEnum(userObject.getBeanEnum());
224                         newUserObject.setHookMethodName(userObject.getHookMethodName());
225                         newUserObject.setHookModuleName(userObject.getHookModuleName());
226                         newUserObject.setHookAllocationMemorySize(
227                             userObject.getHookAllocationMemorySize() + nativeInstance.getSize());
228                         newUserObject.setHookAllocationCount(
229                             userObject.getHookAllocationCount() + nativeInstance.getInstanceCount());
230                         if (nativeInstance.isDeAllocated()) {
231                             newUserObject.setHookDeAllocationCount(
232                                 userObject.getHookDeAllocationCount() + nativeInstance.getInstanceCount());
233                             newUserObject.setHookDeAllocationMemorySize(
234                                 userObject.getHookDeAllocationMemorySize() + nativeInstance.getSize());
235                         } else {
236                             newUserObject.setHookDeAllocationCount(userObject.getHookDeAllocationCount());
237                             newUserObject.setHookDeAllocationMemorySize(userObject.getHookDeAllocationMemorySize());
238                         }
239                         child.setUserObject(newUserObject);
240                         updateParentByAddInstance(child, nativeInstance);
241                     } else {
242                         insertNodeInTreeNode(nativeInstance, nativeFrames, child, index);
243                     }
244                     return;
245                 } else {
246                     insert = true;
247                 }
248             }
249         }
250         addNewNodeAndUpdateParentObject(nativeInstance, nativeFrames, parentNode, startIndex, insert);
251     }
252 
253     /**
254      * doUpdateParentUserObject
255      *
256      * @param nativeInstance nativeInstance
257      * @param nativeFrames nativeFrames
258      * @param parentNode parentNode
259      * @param startIndex startIndex
260      * @param insert insert
261      */
addNewNodeAndUpdateParentObject(NativeInstanceObject nativeInstance, ArrayList<NativeFrame> nativeFrames, DefaultMutableTreeNode parentNode, int startIndex, boolean insert)262     private void addNewNodeAndUpdateParentObject(NativeInstanceObject nativeInstance,
263         ArrayList<NativeFrame> nativeFrames, DefaultMutableTreeNode parentNode, int startIndex, boolean insert) {
264         if (!insert) {
265             return;
266         }
267         if (ProfilerLogManager.isInfoEnabled()) {
268             LOGGER.info("addNewNodeAndUpdateParentObject");
269         }
270         DefaultMutableTreeNode childNode = crateNode(nativeInstance, nativeFrames, startIndex);
271         HookDataBean childNodeUserObject = null;
272         Object userObjectNew = childNode.getUserObject();
273         if (userObjectNew instanceof HookDataBean) {
274             childNodeUserObject = (HookDataBean) userObjectNew;
275         }
276         HookDataBean parNode = null;
277         Object parNodeObject = parentNode.getUserObject();
278         if (parNodeObject instanceof HookDataBean) {
279             parNode = (HookDataBean) parNodeObject;
280         }
281         HookDataBean newParentNode = new HookDataBean();
282         if (parNode != null && childNodeUserObject != null) {
283             newParentNode.setHookMethodName(parNode.getHookMethodName());
284             newParentNode.setHookModuleName(parNode.getHookModuleName());
285             newParentNode.setHookAllocationCount(
286                 parNode.getHookAllocationCount() + childNodeUserObject.getHookAllocationCount());
287             newParentNode.setHookAllocationMemorySize(
288                 parNode.getHookAllocationMemorySize() + childNodeUserObject.getHookAllocationMemorySize());
289             newParentNode.setHookDeAllocationCount(
290                 parNode.getHookDeAllocationCount() + childNodeUserObject.getHookDeAllocationCount());
291             newParentNode.setHookDeAllocationMemorySize(
292                 parNode.getHookDeAllocationMemorySize() + childNodeUserObject.getHookDeAllocationMemorySize());
293             newParentNode.setBeanEnum(parNode.getBeanEnum());
294             parentNode.setUserObject(newParentNode);
295             parentNode.add(childNode);
296             updateParentUserObject(parentNode, childNodeUserObject);
297         }
298     }
299 
updateParentUserObject(DefaultMutableTreeNode parentNode, HookDataBean childNodeUserObject)300     private void updateParentUserObject(DefaultMutableTreeNode parentNode, HookDataBean childNodeUserObject) {
301         if (ProfilerLogManager.isInfoEnabled()) {
302             LOGGER.info("updateParentUserObject");
303         }
304         if (parentNode.isRoot()) {
305             return;
306         }
307         DefaultMutableTreeNode parent = null;
308         Object object = parentNode.getParent();
309         if (object instanceof DefaultMutableTreeNode) {
310             parent = (DefaultMutableTreeNode) object;
311             HookDataBean parNode = null;
312             Object parentUserObject = parent.getUserObject();
313             if (parentUserObject instanceof HookDataBean) {
314                 parNode = (HookDataBean) parentUserObject;
315                 parNode.setHookAllocationCount(
316                     parNode.getHookAllocationCount() + childNodeUserObject.getHookAllocationCount());
317                 parNode.setHookAllocationMemorySize(
318                     parNode.getHookAllocationMemorySize() + childNodeUserObject.getHookAllocationMemorySize());
319                 parNode.setHookDeAllocationCount(
320                     parNode.getHookDeAllocationCount() + childNodeUserObject.getHookDeAllocationCount());
321                 parNode.setHookDeAllocationMemorySize(
322                     parNode.getHookDeAllocationMemorySize() + childNodeUserObject.getHookDeAllocationMemorySize());
323                 parent.setUserObject(parNode);
324                 updateParentUserObject(parent, childNodeUserObject);
325             }
326         }
327     }
328 
updateParentByAddInstance(DefaultMutableTreeNode parentNode, NativeInstanceObject nativeInstance)329     private void updateParentByAddInstance(DefaultMutableTreeNode parentNode, NativeInstanceObject nativeInstance) {
330         if (ProfilerLogManager.isInfoEnabled()) {
331             LOGGER.info("updateParentByAddInstance");
332         }
333         if (parentNode.isRoot()) {
334             return;
335         }
336         DefaultMutableTreeNode parent = null;
337         Object object = parentNode.getParent();
338         if (object instanceof DefaultMutableTreeNode) {
339             parent = (DefaultMutableTreeNode) object;
340             HookDataBean parNode = null;
341             Object parentUserObject = parent.getUserObject();
342             if (parentUserObject instanceof HookDataBean) {
343                 parNode = (HookDataBean) parentUserObject;
344                 parNode.setHookAllocationCount(parNode.getHookAllocationCount() + nativeInstance.getInstanceCount());
345                 parNode.setHookAllocationMemorySize(parNode.getHookAllocationMemorySize() + nativeInstance.getSize());
346                 if (nativeInstance.isDeAllocated()) {
347                     parNode.setHookDeAllocationCount(
348                         parNode.getHookDeAllocationCount() + nativeInstance.getInstanceCount());
349                     parNode.setHookDeAllocationMemorySize(
350                         parNode.getHookDeAllocationMemorySize() + nativeInstance.getSize());
351                 } else {
352                     parNode.setHookDeAllocationCount(parNode.getHookDeAllocationCount());
353                     parNode.setHookDeAllocationMemorySize(parNode.getHookDeAllocationMemorySize());
354                 }
355                 parent.setUserObject(parNode);
356                 updateParentByAddInstance(parent, nativeInstance);
357             }
358         }
359     }
360 
crateNode(NativeInstanceObject nativeInstanceObject, ArrayList<NativeFrame> nativeFrames, int startIndex)361     private DefaultMutableTreeNode crateNode(NativeInstanceObject nativeInstanceObject,
362         ArrayList<NativeFrame> nativeFrames, int startIndex) {
363         if (ProfilerLogManager.isInfoEnabled()) {
364             LOGGER.info("crateNode");
365         }
366         NativeFrame nativeFrame = nativeFrames.get(startIndex);
367         HookDataBean hookDataBean = new HookDataBean();
368         hookDataBean.setHookMethodName(nativeFrame.getFunctionName());
369         hookDataBean.setHookModuleName(nativeFrame.getFileName());
370         hookDataBean.setHookAllocationCount(nativeInstanceObject.getInstanceCount());
371         hookDataBean.setHookAllocationMemorySize(nativeInstanceObject.getSize());
372         if (nativeInstanceObject.isDeAllocated()) {
373             hookDataBean.setHookDeAllocationCount(nativeInstanceObject.getInstanceCount());
374             hookDataBean.setHookDeAllocationMemorySize(nativeInstanceObject.getSize());
375         } else {
376             hookDataBean.setHookDeAllocationCount(0);
377             hookDataBean.setHookDeAllocationMemorySize(0);
378         }
379         if (startIndex < (nativeFrames.size() - 1)) {
380             hookDataBean.setBeanEnum(CALLSTACK_ENUM);
381         } else {
382             hookDataBean.setBeanEnum(MALLOC_ENUM);
383         }
384         DefaultMutableTreeNode endNode = new DefaultMutableTreeNode(hookDataBean);
385         if (startIndex < (nativeFrames.size() - 1)) {
386             int count = startIndex + 1;
387             DefaultMutableTreeNode childNode = crateNode(nativeInstanceObject, nativeFrames, count);
388             endNode.add(childNode);
389             return endNode;
390         }
391         return endNode;
392     }
393 
394     /**
395      * DefaultMutableTreeNode
396      *
397      * @return DefaultMutableTreeNode
398      */
arrangeAllocationMethodDataNode()399     public DefaultMutableTreeNode arrangeAllocationMethodDataNode() {
400         if (ProfilerLogManager.isInfoEnabled()) {
401             LOGGER.info("arrangeAllocationMethodDataNode");
402         }
403         if (nativeData == null || nativeData.size() == 0) {
404             nativeData = dataInterface.getNativeInstanceMap();
405         }
406         Set<String> endCallNamesSet = nativeData.keySet();
407         int totalAllocations = 0;
408         int totalDeallocations = 0;
409         long totalAllocationsSize = 0L;
410         long totalDeallocationsSize = 0L;
411         DefaultMutableTreeNode appNode = new DefaultMutableTreeNode();
412         for (String endCallName : endCallNamesSet) {
413             Collection collections = nativeData.getCollection(endCallName);
414             Iterator iterator = collections.iterator();
415             int myDeltaAllocations = 0;
416             int myDeltaDeallocations = 0;
417             long myDeltaAllocationsSize = 0L;
418             long myDeltaDeallocationsSize = 0L;
419             while (iterator.hasNext()) {
420                 NativeInstanceObject nativeInstance = null;
421                 Object object = iterator.next();
422                 if (object instanceof NativeInstanceObject) {
423                     nativeInstance = (NativeInstanceObject) object;
424                     myDeltaAllocations += nativeInstance.getInstanceCount();
425                     myDeltaAllocationsSize += nativeInstance.getAllowSize();
426                     if (nativeInstance.isDeAllocated()) {
427                         myDeltaDeallocations += nativeInstance.getInstanceCount();
428                         myDeltaDeallocationsSize += nativeInstance.getAllowSize();
429                     }
430                 }
431             }
432             HookDataBean nativeDataBean = new HookDataBean();
433             nativeDataBean.setHookMethodName(endCallName);
434             nativeDataBean.setHookAllocationCount(myDeltaAllocations);
435             nativeDataBean.setHookAllocationMemorySize(myDeltaAllocationsSize);
436             nativeDataBean.setHookDeAllocationCount(myDeltaDeallocations);
437             nativeDataBean.setHookDeAllocationMemorySize(myDeltaDeallocationsSize);
438             nativeDataBean.setBeanEnum(MALLOC_ENUM);
439             appNode.add(new DefaultMutableTreeNode(nativeDataBean));
440             totalAllocations += myDeltaAllocations;
441             totalDeallocations += myDeltaDeallocations;
442             totalAllocationsSize += myDeltaAllocationsSize;
443             totalDeallocationsSize += myDeltaDeallocationsSize;
444         }
445         HookDataBean dataNode =
446             getHookDataBean(totalAllocations, totalDeallocations, totalAllocationsSize, totalDeallocationsSize);
447         appNode.setUserObject(dataNode);
448         return appNode;
449     }
450 
451     /**
452      * getHookDataBean
453      *
454      * @param totalAllocations totalAllocations
455      * @param totalDeallocations totalDeallocations
456      * @param totalAllocationsSize totalAllocationsSize
457      * @param totalDeallocationsSize totalDeallocationsSize
458      * @return HookDataBean
459      */
getHookDataBean(int totalAllocations, int totalDeallocations, long totalAllocationsSize, long totalDeallocationsSize)460     private HookDataBean getHookDataBean(int totalAllocations, int totalDeallocations, long totalAllocationsSize,
461         long totalDeallocationsSize) {
462         if (ProfilerLogManager.isInfoEnabled()) {
463             LOGGER.info("getHookDataBean");
464         }
465         HookDataBean dataNode = new HookDataBean();
466         dataNode.setHookMethodName("Native heap");
467         dataNode.setHookAllocationCount(totalAllocations);
468         dataNode.setHookDeAllocationCount(totalDeallocations);
469         dataNode.setHookAllocationMemorySize(totalAllocationsSize);
470         dataNode.setHookDeAllocationMemorySize(totalDeallocationsSize);
471         dataNode.setBeanEnum(HEAP_ENUM);
472         return dataNode;
473     }
474 
475     /**
476      * treeTable
477      *
478      * @return NativeHookTreeTable
479      */
getTreeTable()480     public NativeHookTreeTable getTreeTable() {
481         return treeTable;
482     }
483 
484     /**
485      * handleInsertSearchText
486      *
487      * @param searchText searchText
488      */
handleInsertSearchText(String searchText)489     public void handleInsertSearchText(String searchText) {
490         this.searchText = searchText;
491         getNodeContainSearch(root, searchText);
492         tableModelOnColumns.setFiltered(false);
493         tableModelOnColumns.reload();
494         treeTable.freshTreeRowExpand();
495     }
496 
497     /**
498      * reset nodes
499      *
500      * @param node node
501      */
resetAllNode(DefaultMutableTreeNode node)502     private void resetAllNode(DefaultMutableTreeNode node) { // Put all nodes in a healthy state of 0
503         Enumeration<TreeNode> enumeration = node.breadthFirstEnumeration();
504         while (enumeration.hasMoreElements()) {
505             TreeNode treNode = enumeration.nextElement();
506             if (treNode instanceof DefaultMutableTreeNode) {
507                 DefaultMutableTreeNode nextElement = (DefaultMutableTreeNode) treNode;
508                 if (nextElement.getUserObject() instanceof HookDataBean) {
509                     ((HookDataBean) nextElement.getUserObject()).setContainType(0);
510                 }
511             }
512         }
513     }
514 
515     /**
516      * handleRemoveSearchText
517      *
518      * @param searchText searchText
519      */
handleRemoveSearchText(String searchText)520     public void handleRemoveSearchText(String searchText) {
521         this.searchText = searchText;
522         if (searchText.isEmpty()) {
523             tableModelOnColumns.setFiltered(true);
524             resetAllNode(root);
525         } else {
526             tableModelOnColumns.setFiltered(false);
527             getNodeContainSearch(root, searchText);
528         }
529         tableModelOnColumns.reload();
530         treeTable.freshTreeRowExpand();
531     }
532 
533     /**
534      * get node contains keyword
535      * Set node type 0 OK 1 based on keywords There are keywords 2 children there keywords 3 no keywords
536      *
537      * @param node node
538      * @param searchText keyword
539      * @return getNodeContainSearch
540      */
getNodeContainSearch(DefaultMutableTreeNode node, String searchText)541     public static boolean getNodeContainSearch(DefaultMutableTreeNode node, String searchText) {
542         boolean hasKeyWord = false;
543         if (searchText == null || searchText.isEmpty()) {
544             return false;
545         }
546         if (!node.isLeaf()) {
547             Enumeration<TreeNode> children = node.children();
548             while (children.hasMoreElements()) {
549                 TreeNode treNode = children.nextElement();
550                 if (treNode instanceof DefaultMutableTreeNode) {
551                     DefaultMutableTreeNode nextElement = (DefaultMutableTreeNode) treNode;
552                     if (nextElement.getUserObject() instanceof HookDataBean) {
553                         HookDataBean bean = (HookDataBean) nextElement.getUserObject();
554                         if (getNodeContainSearch(nextElement, searchText)) {
555                             if (!hasKeyWord) {
556                                 hasKeyWord = true;
557                             }
558                             bean.setContainType(2);
559                             updateContainType(nextElement);
560                         } else {
561                             bean.setContainType(3);
562                         }
563                         if (nextElement.getUserObject().toString().contains(searchText)) {
564                             hasKeyWord = true;
565                             bean.setContainType(1);
566                             updateContainType(nextElement);
567                         }
568                     }
569                 }
570             }
571         } else {
572             if (node.getUserObject() instanceof HookDataBean) {
573                 HookDataBean bean = (HookDataBean) node.getUserObject();
574                 if (bean.getHookMethodName().contains(searchText)) {
575                     hasKeyWord = true;
576                     bean.setContainType(1);
577                 } else {
578                     bean.setContainType(3);
579                 }
580             }
581         }
582         return hasKeyWord;
583     }
584 
updateContainType(DefaultMutableTreeNode node)585     private static void updateContainType(DefaultMutableTreeNode node) {
586         if (node.isLeaf()) {
587             Object userObject = node.getUserObject();
588             if (userObject instanceof HookDataBean) {
589                 HookDataBean bean = (HookDataBean) userObject;
590                 bean.setContainType(2);
591             }
592         } else {
593             Enumeration<TreeNode> children = node.children();
594             while (children.hasMoreElements()) {
595                 TreeNode treNode = children.nextElement();
596                 if (treNode instanceof DefaultMutableTreeNode) {
597                     DefaultMutableTreeNode nextElement = (DefaultMutableTreeNode) treNode;
598                     if (nextElement.getUserObject() instanceof HookDataBean) {
599                         HookDataBean bean = (HookDataBean) nextElement.getUserObject();
600                         bean.setContainType(2);
601                         updateContainType(nextElement);
602                     }
603                 }
604             }
605         }
606     }
607 
608     /**
609      * createTreeTable
610      *
611      * @param root root
612      */
createTreeTable(DefaultMutableTreeNode root)613     public void createTreeTable(DefaultMutableTreeNode root) {
614         if (ProfilerLogManager.isInfoEnabled()) {
615             LOGGER.info("createTreeTable");
616         }
617         tableModelOnColumns = new NativeHookTreeTableModel(root, columns);
618         treeTable = new NativeHookTreeTable(tableModelOnColumns);
619         NativeHookTreeTableRowSorter sorter = new NativeHookTreeTableRowSorter(treeTable.getTable().getModel());
620         treeTable.getTree().addTreeWillExpandListener(new TreeWillExpandListener() {
621             @Override
622             public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
623                 Object lpc = event.getPath().getLastPathComponent();
624                 if (lpc != null && lpc instanceof DefaultMutableTreeNode) {
625                     DefaultMutableTreeNode lastPathComponent = (DefaultMutableTreeNode) lpc;
626                     treeResort(lastPathComponent);
627                 }
628             }
629 
630             @Override
631             public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
632             }
633         });
634         sorter.setListener((columnIndex, sortOrder) -> {
635             if (columnIndex <= 0 || columnIndex > columns.length) {
636                 return;
637             }
638             currentSortKey = columnIndex;
639             currentOrder = sortOrder;
640             treeResort(root);
641             tableModelOnColumns.reload();
642             treeTable.freshTreeExpand();
643         });
644         treeTable.getTree().setRootVisible(true);
645         treeTable.getTree().setExpandsSelectedPaths(true);
646         treeTable.getTable().setRowSorter(sorter);
647         treeTable.getTree().setCellRenderer(new NativeHookTreeTableRenderer());
648         treeTable.getTree().getExpandableItemsHandler().setEnabled(true);
649 
650     }
651 
treeResort(DefaultMutableTreeNode node)652     private void treeResort(DefaultMutableTreeNode node) {
653         if (currentOrder == SortOrder.ASCENDING) {
654             NativeHookTreeTableRowSorter
655                 .sortDescTree(node, columns[currentSortKey].getComparator(), treeTable.getTree());
656         } else {
657             NativeHookTreeTableRowSorter.sortTree(node, columns[currentSortKey].getComparator(), treeTable.getTree());
658         }
659     }
660 
661     /**
662      * refreshNativeHookData
663      *
664      * @param selectItem selectItem
665      * @param text text
666      */
refreshNativeHookData(String selectItem, String text)667     public void refreshNativeHookData(String selectItem, String text) {
668         if ("Arrange by allocation method".equals(selectItem)) {
669             root = arrangeAllocationMethodDataNode();
670         } else {
671             root = arrangeCallStackDataNode();
672         }
673         tableModelOnColumns = new NativeHookTreeTableModel(root, columns);
674         NativeHookTreeTable heapTreeTable = getTreeTable();
675         heapTreeTable.setTreeTableModel(tableModelOnColumns);
676         NativeHookTreeTableRowSorter sorter = new NativeHookTreeTableRowSorter(heapTreeTable.getTable().getModel());
677         sorter.setListener((columnIndex, sortOrder) -> {
678             currentSortKey = columnIndex;
679             currentOrder = sortOrder;
680             treeResort(root);
681             tableModelOnColumns.reload();
682             treeTable.freshTreeExpand();
683         });
684         heapTreeTable.getTable().setRowSorter(sorter);
685     }
686 }
687