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