mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
Changing flow stack snapshot tree node labeling (#26)
* Changing flow stack snapshot tree node labeling * Removing stackObjects node from the hierarchy
This commit is contained in:
parent
a3ab62341c
commit
551a26d0a3
@ -57,7 +57,7 @@ private class FlowStackSnapshotDefaultFactory : FlowStackSnapshotFactory {
|
||||
*/
|
||||
data class FlowStackSnapshot constructor(
|
||||
val timestamp: Long = System.currentTimeMillis(),
|
||||
val flowClass: Class<*>? = null,
|
||||
val flowClass: String? = null,
|
||||
val stackFrames: List<Frame> = listOf()
|
||||
) {
|
||||
data class Frame(
|
||||
|
@ -26,6 +26,7 @@ intellij {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
// For JSON
|
||||
compile "com.fasterxml.jackson.core:jackson-databind:2.8.5"
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import com.intellij.ui.components.JBScrollPane
|
||||
import com.intellij.ui.content.Content
|
||||
import com.intellij.ui.content.ContentFactory
|
||||
import com.intellij.ui.treeStructure.Tree
|
||||
import net.corda.ideaplugin.module.CordaModuleType
|
||||
import java.awt.*
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
@ -187,10 +186,10 @@ class CordaFlowToolWindow : ToolWindowFactory {
|
||||
private class SnapshotTreeRenderer : DefaultTreeCellRenderer() {
|
||||
override fun getTreeCellRendererComponent(tree: JTree?, value: Any?, sel: Boolean, expanded: Boolean, leaf: Boolean, row: Int, hasFocus: Boolean): Component {
|
||||
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus)
|
||||
val descriptor = (value as DefaultMutableTreeNode).userObject as SnapshotDataDescriptor
|
||||
val descriptor = (value as DefaultMutableTreeNode).userObject as Descriptor
|
||||
icon = descriptor.icon
|
||||
if (!descriptor.key.isNullOrEmpty()) {
|
||||
text = "${descriptor.key}: ${descriptor.data.toString()}"
|
||||
if (!descriptor.label.isNullOrEmpty()) {
|
||||
text = descriptor.label + if (leaf) ": ${descriptor.value?.toString()}" else ""
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.corda.ideaplugin.toolwindow
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.intellij.icons.AllIcons
|
||||
import net.corda.core.flows.FlowStackSnapshot
|
||||
import java.io.File
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JTree
|
||||
@ -10,13 +11,6 @@ import javax.swing.tree.DefaultMutableTreeNode
|
||||
import javax.swing.tree.DefaultTreeModel
|
||||
import javax.swing.tree.MutableTreeNode
|
||||
|
||||
/**
|
||||
* Snapshot tree data descriptor. It is used as userObject in the [DefaultMutableTreeNode] class.
|
||||
*/
|
||||
class SnapshotDataDescriptor(val data: Any?, val icon: Icon, val key: String? = null) {
|
||||
override fun toString(): String = data?.toString() ?: "null"
|
||||
}
|
||||
|
||||
/**
|
||||
* Manager class for flow snapshots. It is responsible for parsing data read from a snapshot file and constructing
|
||||
* tree model from it.
|
||||
@ -27,7 +21,7 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
||||
}
|
||||
|
||||
// Root node for the snapshot hierarchy, which is an empty node.
|
||||
private val root = DefaultMutableTreeNode(SnapshotDataDescriptor(null, AllIcons.Json.Object))
|
||||
private val root = DefaultMutableTreeNode(Descriptor())
|
||||
// Snapshot tree model
|
||||
private val snapshotModel = DefaultTreeModel(root)
|
||||
|
||||
@ -62,8 +56,8 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
||||
* the model is updated accordingly.
|
||||
*/
|
||||
fun addNodeToSnapshotModel(snapshotFile: File) {
|
||||
val insertionIndex = -(root.childNodes().map {
|
||||
(it.userObject as SnapshotDataDescriptor).key
|
||||
val insertionIndex = -(root.childNodes.map {
|
||||
it.file?.name
|
||||
}.binarySearch(extractFileName(snapshotFile))) - 1
|
||||
insertNodeToSnapshotModel(snapshotFile, insertionIndex)
|
||||
}
|
||||
@ -72,8 +66,9 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
||||
* Removes the snapshot file from the snapshot hierarchy. The model is also updated after this operation.
|
||||
*/
|
||||
fun removeNodeFromSnapshotModel(snapshotFile: File) {
|
||||
val node = root.childNodes().find {
|
||||
(it.userObject as SnapshotDataDescriptor).data == extractFileName(snapshotFile)
|
||||
val snapshotFileName = extractFileName(snapshotFile)
|
||||
val node = root.childNodes.find {
|
||||
it.file?.name == snapshotFileName
|
||||
} as MutableTreeNode?
|
||||
if (node != null) {
|
||||
snapshotModel.removeNodeFromParent(node)
|
||||
@ -83,7 +78,23 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
||||
}
|
||||
|
||||
private fun insertNodeToSnapshotModel(snapshotFile: File, insertionIndex: Int = -1) {
|
||||
buildChildrenModel(mapper.readTree(snapshotFile), root, extractFileName(snapshotFile), insertionIndex)
|
||||
val fileNode = DefaultMutableTreeNode(Descriptor(snapshotFile, AllIcons.FileTypes.Custom, snapshotFile.name))
|
||||
val snapshot = mapper.readValue(snapshotFile, FlowStackSnapshot::class.java)
|
||||
fileNode.add(DefaultMutableTreeNode(Descriptor(snapshot.timestamp, AllIcons.Debugger.Db_primitive, "timestamp")))
|
||||
fileNode.add(DefaultMutableTreeNode(Descriptor(snapshot.flowClass, AllIcons.Debugger.Db_primitive, "flowClass")))
|
||||
val framesNode = DefaultMutableTreeNode(Descriptor(icon = AllIcons.Debugger.Db_array, label = "stackFrames"))
|
||||
fileNode.add(framesNode)
|
||||
snapshot.stackFrames.forEach {
|
||||
val ste = it.stackTraceElement!!
|
||||
val label = "${ste.className}.${ste.methodName}(line:${ste.lineNumber}) - ${ste.fileName}"
|
||||
val frameNode = DefaultMutableTreeNode(Descriptor(icon = AllIcons.Debugger.StackFrame, label = label))
|
||||
framesNode.add(frameNode)
|
||||
it.stackObjects.mapIndexed { index: Int, stackItem: Any? ->
|
||||
buildChildrenModel(mapper.convertValue(stackItem, JsonNode::class.java), frameNode, index.toString())
|
||||
}
|
||||
}
|
||||
|
||||
addToModelAndRefresh(snapshotModel, fileNode, root, insertionIndex)
|
||||
}
|
||||
|
||||
private fun extractFileName(file: File): String {
|
||||
@ -92,26 +103,26 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
||||
|
||||
private fun buildChildrenModel(
|
||||
node: JsonNode?,
|
||||
parent: DefaultMutableTreeNode, key: String? = null,
|
||||
insertionIndex: Int = -1) {
|
||||
parent: DefaultMutableTreeNode, label: String? = null) {
|
||||
val child: DefaultMutableTreeNode
|
||||
if (node == null || !node.isContainerNode) {
|
||||
child = DefaultMutableTreeNode(SnapshotDataDescriptor(node, AllIcons.Debugger.Db_primitive, key))
|
||||
addToModelAndRefresh(snapshotModel, child, parent, insertionIndex)
|
||||
parent.add(DefaultMutableTreeNode(Descriptor(node, AllIcons.Debugger.Db_primitive, label)))
|
||||
} else {
|
||||
if (node.isArray) {
|
||||
child = DefaultMutableTreeNode(SnapshotDataDescriptor(key, AllIcons.Debugger.Db_array))
|
||||
addToModelAndRefresh(snapshotModel, child, parent, insertionIndex)
|
||||
child = DefaultMutableTreeNode(Descriptor(icon = AllIcons.Debugger.Db_array, label = label))
|
||||
parent.add(child)
|
||||
node.mapIndexed { index: Int, item: JsonNode? ->
|
||||
buildChildrenModel(item, child, index.toString())
|
||||
}
|
||||
} else {
|
||||
child = DefaultMutableTreeNode(SnapshotDataDescriptor(key, AllIcons.Json.Object))
|
||||
addToModelAndRefresh(snapshotModel, child, parent, insertionIndex)
|
||||
child = DefaultMutableTreeNode(Descriptor(icon = AllIcons.Json.Object, label = label))
|
||||
parent.add(child)
|
||||
node.fields().forEach {
|
||||
buildChildrenModel(it.value, child, it.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Descriptor(val value:Any? = null, val icon: Icon? = null, val label:String? = null)
|
@ -39,7 +39,7 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
||||
* Builds the flow directory hierarchy with the root being associated with the passed [flowsDirectory].
|
||||
* If the parameter is missing the function rebuilds current hierarchy and reloads (refreshes) current model.
|
||||
*/
|
||||
fun loadFlows(flowsDirectory: File? = root.userObjectAsFile()) {
|
||||
fun loadFlows(flowsDirectory: File? = root.file) {
|
||||
root.userObject = flowsDirectory ?: return
|
||||
root.removeAllChildren()
|
||||
|
||||
@ -81,8 +81,8 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
||||
}
|
||||
|
||||
private fun isSelected(dir: File?): Boolean {
|
||||
val node = tree.selectedNode()
|
||||
return node != null && dir == node.userObjectAsFile()
|
||||
val node = tree.selectedNode
|
||||
return node != null && dir == node.file
|
||||
}
|
||||
|
||||
private fun startWatching(dir: File) {
|
||||
@ -100,18 +100,18 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
||||
val parent = dir.parentFile
|
||||
if (parent.name == FLOWS_DIRECTORY) {
|
||||
// if a date directory has been added this means that that its parent is [FLOWS_DIRECTORY]
|
||||
insertDateDirectory(dir, findInsertionIndex(root.childNodes(), dir.name))
|
||||
insertDateDirectory(dir, findInsertionIndex(root.childNodes, dir.name))
|
||||
} else if (parent.parentFile.name == FLOWS_DIRECTORY) {
|
||||
// if a flow directory has been added this means that that the parent of its parent is [FLOWS_DIRECTORY]
|
||||
val parentNode = root.childNodes().findByFile(parent) ?: return
|
||||
flowModel.insertNodeInto(DefaultMutableTreeNode(dir), parentNode, findInsertionIndex(parentNode.childNodes(), dir.name))
|
||||
val parentNode = root.childNodes.findByFile(parent) ?: return
|
||||
flowModel.insertNodeInto(DefaultMutableTreeNode(dir), parentNode, findInsertionIndex(parentNode.childNodes, dir.name))
|
||||
startWatching(dir)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeNodeFromFlowModel(dir: File) {
|
||||
val selectedNode = tree.selectedNode()
|
||||
if (selectedNode != null && selectedNode.userObjectAsFile() == dir) {
|
||||
val selectedNode = tree.selectedNode
|
||||
if (selectedNode != null && selectedNode.file == dir) {
|
||||
// Reload flows if the [dir] is currently selected
|
||||
loadFlows()
|
||||
return
|
||||
@ -123,10 +123,10 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
||||
parentNode = root
|
||||
} else if (parent.parentFile.name == FLOWS_DIRECTORY) {
|
||||
// if a flow directory has been added this means that that the parent of its parent is [FLOWS_DIRECTORY]
|
||||
parentNode = root.childNodes().findByFile(parent)
|
||||
parentNode = root.childNodes.findByFile(parent)
|
||||
}
|
||||
if (parentNode != null) {
|
||||
val node = parentNode.childNodes().findByFile(dir) ?: return
|
||||
val node = parentNode.childNodes.findByFile(dir) ?: return
|
||||
flowModel.removeNodeFromParent(node)
|
||||
}
|
||||
}
|
||||
@ -206,10 +206,10 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
||||
}
|
||||
}
|
||||
|
||||
internal fun DefaultMutableTreeNode.userObjectAsFile() = userObject as? File
|
||||
internal fun DefaultMutableTreeNode.childNodes() = children().toList().mapNotNull { it as? DefaultMutableTreeNode }
|
||||
private fun List<DefaultMutableTreeNode>.findByFile(file: File) = find { it.userObjectAsFile() == file }
|
||||
private fun JTree.selectedNode() = lastSelectedPathComponent as? DefaultMutableTreeNode
|
||||
internal val DefaultMutableTreeNode.file get() = userObject as? File
|
||||
internal val DefaultMutableTreeNode.childNodes get() = children().toList().mapNotNull { it as? DefaultMutableTreeNode }
|
||||
private val JTree.selectedNode get() = lastSelectedPathComponent as? DefaultMutableTreeNode
|
||||
private fun List<DefaultMutableTreeNode>.findByFile(file: File) = find { it.file == file }
|
||||
|
||||
internal fun addToModelAndRefresh(model: DefaultTreeModel,
|
||||
child: DefaultMutableTreeNode,
|
||||
|
@ -70,7 +70,7 @@ class FlowStackSnapshotFactoryImpl : FlowStackSnapshotFactory {
|
||||
Frame(element, listOf())
|
||||
}
|
||||
}
|
||||
return FlowStackSnapshot(flowClass = flowClass, stackFrames = frames)
|
||||
return FlowStackSnapshot(flowClass = flowClass.name, stackFrames = frames)
|
||||
}
|
||||
|
||||
private fun getInstrumentedAnnotation(element: StackTraceElement): Instrumented? {
|
||||
|
Loading…
Reference in New Issue
Block a user