mirror of
https://github.com/corda/corda.git
synced 2024-12-28 16:58:55 +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(
|
data class FlowStackSnapshot constructor(
|
||||||
val timestamp: Long = System.currentTimeMillis(),
|
val timestamp: Long = System.currentTimeMillis(),
|
||||||
val flowClass: Class<*>? = null,
|
val flowClass: String? = null,
|
||||||
val stackFrames: List<Frame> = listOf()
|
val stackFrames: List<Frame> = listOf()
|
||||||
) {
|
) {
|
||||||
data class Frame(
|
data class Frame(
|
||||||
|
@ -26,6 +26,7 @@ intellij {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compile project(':core')
|
||||||
// For JSON
|
// For JSON
|
||||||
compile "com.fasterxml.jackson.core:jackson-databind:2.8.5"
|
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.Content
|
||||||
import com.intellij.ui.content.ContentFactory
|
import com.intellij.ui.content.ContentFactory
|
||||||
import com.intellij.ui.treeStructure.Tree
|
import com.intellij.ui.treeStructure.Tree
|
||||||
import net.corda.ideaplugin.module.CordaModuleType
|
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.awt.event.MouseAdapter
|
import java.awt.event.MouseAdapter
|
||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
@ -187,10 +186,10 @@ class CordaFlowToolWindow : ToolWindowFactory {
|
|||||||
private class SnapshotTreeRenderer : DefaultTreeCellRenderer() {
|
private class SnapshotTreeRenderer : DefaultTreeCellRenderer() {
|
||||||
override fun getTreeCellRendererComponent(tree: JTree?, value: Any?, sel: Boolean, expanded: Boolean, leaf: Boolean, row: Int, hasFocus: Boolean): Component {
|
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)
|
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
|
icon = descriptor.icon
|
||||||
if (!descriptor.key.isNullOrEmpty()) {
|
if (!descriptor.label.isNullOrEmpty()) {
|
||||||
text = "${descriptor.key}: ${descriptor.data.toString()}"
|
text = descriptor.label + if (leaf) ": ${descriptor.value?.toString()}" else ""
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.ideaplugin.toolwindow
|
|||||||
import com.fasterxml.jackson.databind.JsonNode
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.intellij.icons.AllIcons
|
import com.intellij.icons.AllIcons
|
||||||
|
import net.corda.core.flows.FlowStackSnapshot
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
import javax.swing.JTree
|
import javax.swing.JTree
|
||||||
@ -10,13 +11,6 @@ import javax.swing.tree.DefaultMutableTreeNode
|
|||||||
import javax.swing.tree.DefaultTreeModel
|
import javax.swing.tree.DefaultTreeModel
|
||||||
import javax.swing.tree.MutableTreeNode
|
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
|
* Manager class for flow snapshots. It is responsible for parsing data read from a snapshot file and constructing
|
||||||
* tree model from it.
|
* tree model from it.
|
||||||
@ -27,7 +21,7 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Root node for the snapshot hierarchy, which is an empty node.
|
// 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
|
// Snapshot tree model
|
||||||
private val snapshotModel = DefaultTreeModel(root)
|
private val snapshotModel = DefaultTreeModel(root)
|
||||||
|
|
||||||
@ -62,8 +56,8 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
|||||||
* the model is updated accordingly.
|
* the model is updated accordingly.
|
||||||
*/
|
*/
|
||||||
fun addNodeToSnapshotModel(snapshotFile: File) {
|
fun addNodeToSnapshotModel(snapshotFile: File) {
|
||||||
val insertionIndex = -(root.childNodes().map {
|
val insertionIndex = -(root.childNodes.map {
|
||||||
(it.userObject as SnapshotDataDescriptor).key
|
it.file?.name
|
||||||
}.binarySearch(extractFileName(snapshotFile))) - 1
|
}.binarySearch(extractFileName(snapshotFile))) - 1
|
||||||
insertNodeToSnapshotModel(snapshotFile, insertionIndex)
|
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.
|
* Removes the snapshot file from the snapshot hierarchy. The model is also updated after this operation.
|
||||||
*/
|
*/
|
||||||
fun removeNodeFromSnapshotModel(snapshotFile: File) {
|
fun removeNodeFromSnapshotModel(snapshotFile: File) {
|
||||||
val node = root.childNodes().find {
|
val snapshotFileName = extractFileName(snapshotFile)
|
||||||
(it.userObject as SnapshotDataDescriptor).data == extractFileName(snapshotFile)
|
val node = root.childNodes.find {
|
||||||
|
it.file?.name == snapshotFileName
|
||||||
} as MutableTreeNode?
|
} as MutableTreeNode?
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
snapshotModel.removeNodeFromParent(node)
|
snapshotModel.removeNodeFromParent(node)
|
||||||
@ -83,7 +78,23 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun insertNodeToSnapshotModel(snapshotFile: File, insertionIndex: Int = -1) {
|
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 {
|
private fun extractFileName(file: File): String {
|
||||||
@ -92,22 +103,20 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
|||||||
|
|
||||||
private fun buildChildrenModel(
|
private fun buildChildrenModel(
|
||||||
node: JsonNode?,
|
node: JsonNode?,
|
||||||
parent: DefaultMutableTreeNode, key: String? = null,
|
parent: DefaultMutableTreeNode, label: String? = null) {
|
||||||
insertionIndex: Int = -1) {
|
|
||||||
val child: DefaultMutableTreeNode
|
val child: DefaultMutableTreeNode
|
||||||
if (node == null || !node.isContainerNode) {
|
if (node == null || !node.isContainerNode) {
|
||||||
child = DefaultMutableTreeNode(SnapshotDataDescriptor(node, AllIcons.Debugger.Db_primitive, key))
|
parent.add(DefaultMutableTreeNode(Descriptor(node, AllIcons.Debugger.Db_primitive, label)))
|
||||||
addToModelAndRefresh(snapshotModel, child, parent, insertionIndex)
|
|
||||||
} else {
|
} else {
|
||||||
if (node.isArray) {
|
if (node.isArray) {
|
||||||
child = DefaultMutableTreeNode(SnapshotDataDescriptor(key, AllIcons.Debugger.Db_array))
|
child = DefaultMutableTreeNode(Descriptor(icon = AllIcons.Debugger.Db_array, label = label))
|
||||||
addToModelAndRefresh(snapshotModel, child, parent, insertionIndex)
|
parent.add(child)
|
||||||
node.mapIndexed { index: Int, item: JsonNode? ->
|
node.mapIndexed { index: Int, item: JsonNode? ->
|
||||||
buildChildrenModel(item, child, index.toString())
|
buildChildrenModel(item, child, index.toString())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
child = DefaultMutableTreeNode(SnapshotDataDescriptor(key, AllIcons.Json.Object))
|
child = DefaultMutableTreeNode(Descriptor(icon = AllIcons.Json.Object, label = label))
|
||||||
addToModelAndRefresh(snapshotModel, child, parent, insertionIndex)
|
parent.add(child)
|
||||||
node.fields().forEach {
|
node.fields().forEach {
|
||||||
buildChildrenModel(it.value, child, it.key)
|
buildChildrenModel(it.value, child, it.key)
|
||||||
}
|
}
|
||||||
@ -115,3 +124,5 @@ class FlowSnapshotTreeDataManager(tree: JTree) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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].
|
* 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.
|
* 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.userObject = flowsDirectory ?: return
|
||||||
root.removeAllChildren()
|
root.removeAllChildren()
|
||||||
|
|
||||||
@ -81,8 +81,8 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isSelected(dir: File?): Boolean {
|
private fun isSelected(dir: File?): Boolean {
|
||||||
val node = tree.selectedNode()
|
val node = tree.selectedNode
|
||||||
return node != null && dir == node.userObjectAsFile()
|
return node != null && dir == node.file
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startWatching(dir: File) {
|
private fun startWatching(dir: File) {
|
||||||
@ -100,18 +100,18 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
|||||||
val parent = dir.parentFile
|
val parent = dir.parentFile
|
||||||
if (parent.name == FLOWS_DIRECTORY) {
|
if (parent.name == FLOWS_DIRECTORY) {
|
||||||
// if a date directory has been added this means that that its parent is [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) {
|
} 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]
|
// 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
|
val parentNode = root.childNodes.findByFile(parent) ?: return
|
||||||
flowModel.insertNodeInto(DefaultMutableTreeNode(dir), parentNode, findInsertionIndex(parentNode.childNodes(), dir.name))
|
flowModel.insertNodeInto(DefaultMutableTreeNode(dir), parentNode, findInsertionIndex(parentNode.childNodes, dir.name))
|
||||||
startWatching(dir)
|
startWatching(dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeNodeFromFlowModel(dir: File) {
|
private fun removeNodeFromFlowModel(dir: File) {
|
||||||
val selectedNode = tree.selectedNode()
|
val selectedNode = tree.selectedNode
|
||||||
if (selectedNode != null && selectedNode.userObjectAsFile() == dir) {
|
if (selectedNode != null && selectedNode.file == dir) {
|
||||||
// Reload flows if the [dir] is currently selected
|
// Reload flows if the [dir] is currently selected
|
||||||
loadFlows()
|
loadFlows()
|
||||||
return
|
return
|
||||||
@ -123,10 +123,10 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
|||||||
parentNode = root
|
parentNode = root
|
||||||
} else if (parent.parentFile.name == FLOWS_DIRECTORY) {
|
} 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]
|
// 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) {
|
if (parentNode != null) {
|
||||||
val node = parentNode.childNodes().findByFile(dir) ?: return
|
val node = parentNode.childNodes.findByFile(dir) ?: return
|
||||||
flowModel.removeNodeFromParent(node)
|
flowModel.removeNodeFromParent(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,10 +206,10 @@ class FlowTreeDataManager(val tree: JTree, val snapshotModel: FlowSnapshotTreeDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun DefaultMutableTreeNode.userObjectAsFile() = userObject as? File
|
internal val DefaultMutableTreeNode.file get() = userObject as? File
|
||||||
internal fun DefaultMutableTreeNode.childNodes() = children().toList().mapNotNull { it as? DefaultMutableTreeNode }
|
internal val DefaultMutableTreeNode.childNodes get() = children().toList().mapNotNull { it as? DefaultMutableTreeNode }
|
||||||
private fun List<DefaultMutableTreeNode>.findByFile(file: File) = find { it.userObjectAsFile() == file }
|
private val JTree.selectedNode get() = lastSelectedPathComponent as? DefaultMutableTreeNode
|
||||||
private fun JTree.selectedNode() = lastSelectedPathComponent as? DefaultMutableTreeNode
|
private fun List<DefaultMutableTreeNode>.findByFile(file: File) = find { it.file == file }
|
||||||
|
|
||||||
internal fun addToModelAndRefresh(model: DefaultTreeModel,
|
internal fun addToModelAndRefresh(model: DefaultTreeModel,
|
||||||
child: DefaultMutableTreeNode,
|
child: DefaultMutableTreeNode,
|
||||||
|
@ -70,7 +70,7 @@ class FlowStackSnapshotFactoryImpl : FlowStackSnapshotFactory {
|
|||||||
Frame(element, listOf())
|
Frame(element, listOf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FlowStackSnapshot(flowClass = flowClass, stackFrames = frames)
|
return FlowStackSnapshot(flowClass = flowClass.name, stackFrames = frames)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInstrumentedAnnotation(element: StackTraceElement): Instrumented? {
|
private fun getInstrumentedAnnotation(element: StackTraceElement): Instrumented? {
|
||||||
|
Loading…
Reference in New Issue
Block a user