001package org.javasimon.callback.calltree; 002 003import java.util.LinkedList; 004 005import org.javasimon.Split; 006import org.javasimon.callback.logging.LogMessageSource; 007 008/** 009 * Call tree contains the root call tree node and the current call stack. 010 * 011 * @author gquintana 012 * @since 3.2 013 */ 014public class CallTree implements LogMessageSource<Split> { 015 016 // TODO in what unit? 017 /** Log threshold. */ 018 private final Long logThreshold; 019 020 /** Call stack is the path (made of tree nodes) from root tree node to the current tree node. */ 021 private final LinkedList<CallTreeNode> callStack = new LinkedList<>(); 022 023 /** Root call tree node. */ 024 private CallTreeNode rootNode; 025 026 /** 027 * Main constructor. 028 * 029 * @param logThreshold Log threshold 030 */ 031 public CallTree(Long logThreshold) { 032 this.logThreshold = logThreshold; 033 } 034 035 /** 036 * When stopwatch is started, a new tree node is added to the parent 037 * tree node and pushed on the call stack. 038 * As a result, child tree node becomes the current tree node. 039 * 040 * @return Current (child) tree node 041 */ 042 public CallTreeNode onStopwatchStart(Split split) { 043 final String name = split.getStopwatch().getName(); 044 CallTreeNode currentNode; 045 if (callStack.isEmpty()) { 046 // Root tree node 047 rootNode = new CallTreeNode(name); 048 currentNode = rootNode; 049 onRootStopwatchStart(currentNode, split); 050 } else { 051 // Child node 052 currentNode = callStack.getLast().getOrAddChild(name); 053 } 054 callStack.addLast(currentNode); 055 return currentNode; 056 } 057 058 /** 059 * When stopwatch is stopped, the the split is added to current tree node 060 * and this tree node is popped from call stack. 061 * As a result, parent tree node becomes current tree node. 062 * 063 * @return Current (child) tree node 064 */ 065 public CallTreeNode onStopwatchStop(Split split) { 066 CallTreeNode currentNode = callStack.removeLast(); 067 currentNode.addSplit(split); 068 if (callStack.isEmpty()) { 069 onRootStopwatchStop(currentNode, split); 070 } 071 return currentNode; 072 } 073 074 /** 075 * When stopwatch is started, and the root tree node is pushed into 076 * the call stack, this method is called. 077 * Does nothing but can be overridden for custom needs. 078 * 079 * @param rootNode Root tree node 080 * @param split Root split 081 */ 082 public void onRootStopwatchStart(CallTreeNode rootNode, Split split) { 083 } 084 085 /** 086 * When stopwatch is stopped, and root tree node is popped from 087 * call stack, this method is called. 088 * Does nothing but can be overridden for custom needs, such as logging, storing... 089 */ 090 protected void onRootStopwatchStop(CallTreeNode callTreeNode, Split split) { 091 } 092 093 /** 094 * Transforms this call tree into a loggable message. 095 */ 096 public String getLogMessage(Split context) { 097 context.getStopwatch().setAttribute(CallTreeCallback.ATTR_NAME_LAST, this); 098 return "Call Tree:\r\n" + rootNode.toString(); 099 } 100 101 public Long getLogThreshold() { 102 return logThreshold; 103 } 104 105 public CallTreeNode getRootNode() { 106 return rootNode; 107 } 108}