From daaec5509500432651fff57907a84ee1de3e6acb Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Thu, 25 Oct 2018 23:08:06 +0100 Subject: [PATCH 01/21] #19 create report service --- .../ephyra/acropolis/service/api/IReportService.kt | 14 ++++++++++++++ .../ephyra/acropolis/service/impl/ReportService.kt | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IReportService.kt create mode 100644 acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IReportService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IReportService.kt new file mode 100644 index 0000000..5607014 --- /dev/null +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IReportService.kt @@ -0,0 +1,14 @@ +package org.ephyra.acropolis.service.api + +/** + * Service for creation reports on a project. + * These may be different formats and contain all or a subset of the data contained in the project. + */ +interface IReportService { + /** + * Create a report which contains details of the software in the given project + * + * @param projectName The name of the project to run the report on + */ + fun runSoftwareReport(projectName: String) +} diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt new file mode 100644 index 0000000..9325a86 --- /dev/null +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt @@ -0,0 +1,14 @@ +package org.ephyra.acropolis.service.impl + +import org.ephyra.acropolis.service.api.IReportService +import org.springframework.stereotype.Service + +/** + * Report service implementation + */ +@Service +class ReportService : IReportService { + override fun runSoftwareReport(projectName: String) { + + } +} From a4bd70668ebd742708c23b9b350e2e5a12bda0ef Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Fri, 26 Oct 2018 17:44:23 +0100 Subject: [PATCH 02/21] #19 Create report module and define data model --- acropolis-report/build.gradle | 69 +++++++++++++++++++ .../acropolis/report/api/IReportRunner.kt | 7 ++ .../acropolis/report/api/model/Graph.kt | 50 ++++++++++++++ .../report/config/ReportConfiguration.kt | 8 +++ .../acropolis/report/impl/ReportRunner.kt | 12 ++++ acropolis-service/build.gradle | 1 + .../service/config/ServiceConfiguration.kt | 2 +- .../acropolis/service/impl/ReportService.kt | 20 ++++++ settings.gradle | 3 +- 9 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 acropolis-report/build.gradle create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt diff --git a/acropolis-report/build.gradle b/acropolis-report/build.gradle new file mode 100644 index 0000000..2d2bc9a --- /dev/null +++ b/acropolis-report/build.gradle @@ -0,0 +1,69 @@ +buildscript { + ext { + kotlinVersion = "1.2.71" + } + repositories { + jcenter() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion" + } +} + +apply plugin: 'kotlin' +apply plugin: 'jacoco' + +sourceCompatibility = 1.8 +compileKotlin { + kotlinOptions { + freeCompilerArgs = ["-Xjsr305=strict"] + jvmTarget = "1.8" + } +} + +jacoco { + toolVersion = '0.8.2' +} + +jacocoTestReport { + reports { + xml.enabled = true + html.enabled = true + csv.enabled = false + } +} + +jacocoTestCoverageVerification { + violationRules { + rule { + limit { + minimum = 0.9 + } + } + } +} + +test { + useJUnitPlatform() +} + +dependencies { + // The Kotlin standard library + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + + // https://mvnrepository.com/artifact/org.slf4j/slf4j-api + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25' + + // https://mvnrepository.com/artifact/org.springframework/spring-context + compile group: 'org.springframework', name: 'spring-context', version: '5.1.1.RELEASE' + + // https://mvnrepository.com/artifact/ch.qos.logback/logback-classic + testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3' + + // https://mvnrepository.com/artifact/io.kotlintest/kotlintest-runner-junit5 + testCompile "io.kotlintest:kotlintest-runner-junit5:3.1.9" + + // https://mvnrepository.com/artifact/io.mockk/mockk + testCompile "io.mockk:mockk:1.8.7" +} diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt new file mode 100644 index 0000000..6aa8589 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt @@ -0,0 +1,7 @@ +package org.ephyra.acropolis.report.api + +import org.ephyra.acropolis.report.api.model.GraphContainer + +interface IReportRunner { + fun run(graphContainer: GraphContainer) +} diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt new file mode 100644 index 0000000..e73a6c5 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt @@ -0,0 +1,50 @@ +package org.ephyra.acropolis.report.api.model + +class GraphContainer( + val graph: Graph +) { + private val subGraphs: MutableList = ArrayList() + + fun defineSubgraph(name: String, includeNodes: List) { + subGraphs.add(SubGraphSelector(name, includeNodes)) + } +} + +class Graph { + private val nodes: MutableSet = HashSet() + + private val edges: MutableList = ArrayList() + + fun addNode(node: Node) { + nodes.add(node) + } + + fun addEdge(n1: Node, n2: Node) { + edges.add(Edge(n1, n2, false)) + } + + fun addDirectedEdge(from: Node, to: Node) { + edges.add(Edge(from, to, true)) + } +} + +class Node( + val label: String +) { +} + +class Edge( + val source: Node, + + val sink: Node, + + val directed: Boolean = false +) { +} + +class SubGraphSelector ( + val name: String, + + val includeNodes: List +) { +} diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt new file mode 100644 index 0000000..1f3c6e8 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt @@ -0,0 +1,8 @@ +package org.ephyra.acropolis.report.config + +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration + +@Configuration +@ComponentScan(basePackages = ["org.ephyra.acropolis.report.config", "org.ephyra.acropolis.report.impl"]) +open class ReportConfiguration diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt new file mode 100644 index 0000000..78eafd3 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -0,0 +1,12 @@ +package org.ephyra.acropolis.report.impl + +import org.ephyra.acropolis.report.api.IReportRunner +import org.ephyra.acropolis.report.api.model.GraphContainer +import org.springframework.stereotype.Component + +@Component +private class ReportRunner : IReportRunner { + override fun run(graphContainer: GraphContainer) { + println("Running report") + } +} diff --git a/acropolis-service/build.gradle b/acropolis-service/build.gradle index 9383c3e..e5eb951 100644 --- a/acropolis-service/build.gradle +++ b/acropolis-service/build.gradle @@ -92,6 +92,7 @@ dependencies { compile project(":acropolis-persistence") compile project(":acropolis-external") + compile project(":acropolis-report") // https://mvnrepository.com/artifact/io.kotlintest/kotlintest-runner-junit5 testCompile "io.kotlintest:kotlintest-runner-junit5:3.1.9" diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt index a65b660..e582c64 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt @@ -8,5 +8,5 @@ import org.springframework.context.annotation.Configuration * in order to configure this module correctly. */ @Configuration -@ComponentScan(basePackages = ["org.ephyra.acropolis.persistence.config", "org.ephyra.acropolis.service.impl"]) +@ComponentScan(basePackages = ["org.ephyra.acropolis.persistence.config", "org.ephyra.acropolis.report.config", "org.ephyra.acropolis.service.impl"]) class ServiceConfiguration diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt index 9325a86..a829a93 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt @@ -1,6 +1,12 @@ package org.ephyra.acropolis.service.impl +import org.ephyra.acropolis.report.api.IReportRunner +import org.ephyra.acropolis.service.api.IApplicationSoftwareService import org.ephyra.acropolis.service.api.IReportService +import org.ephyra.acropolis.service.api.ISystemSoftwareService +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service /** @@ -8,7 +14,21 @@ import org.springframework.stereotype.Service */ @Service class ReportService : IReportService { + private val logger: Logger = LoggerFactory.getLogger(ApplicationSoftwareService::class.java) + + @Autowired + private lateinit var applicationService: IApplicationSoftwareService + + @Autowired + private lateinit var systemService: ISystemSoftwareService + + @Autowired + private lateinit var reportRunner: IReportRunner + override fun runSoftwareReport(projectName: String) { + logger.trace("Starting to run software report for project [$projectName]") + applicationService.findAll(projectName) + systemService.findAll(projectName) } } diff --git a/settings.gradle b/settings.gradle index ceae395..098e6bd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ rootProject.name = "Acropolis" -include "acropolis-shell", "acropolis-service", "acropolis-persistence", "acropolis-rest", "acropolis-external" +include "acropolis-shell", "acropolis-service", "acropolis-persistence", "acropolis-rest", + "acropolis-external", "acropolis-report" From 0e41d7763b209b0b132c806b2983be2c97e4ded7 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sat, 27 Oct 2018 12:22:43 +0100 Subject: [PATCH 03/21] #19 create initial helper for rendering diagrams using java2d --- .../report/impl/render/DiagramRenderer.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt new file mode 100644 index 0000000..655c7e7 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -0,0 +1,37 @@ +package org.ephyra.acropolis.report.impl.render + +import java.awt.Color +import java.awt.Graphics2D +import java.awt.image.BufferedImage +import java.awt.image.BufferedImage.TYPE_INT_RGB +import java.io.File +import javax.imageio.ImageIO + +class DiagramRenderer( + private val width: Int, + + private val height: Int +) : AutoCloseable { + private val targetImg: BufferedImage = BufferedImage(width, height, TYPE_INT_RGB) + private val target: Graphics2D + + init { + target = targetImg.createGraphics() + + target.color = Color.WHITE + target.fillRect(0, 0, width, height) + } + + fun addImage(positionX: Int, positionY: Int, source: File) { + val img = ImageIO.read(source) + target.drawImage(img, positionX, positionY, img.width, img.height, null) + } + + fun export(outFile: File) { + ImageIO.write(targetImg, outFile.extension, outFile) + } + + override fun close() { + target.dispose() + } +} From abc7fd36cea987f53b33f79745c7356074c07a77 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sat, 27 Oct 2018 14:14:06 +0100 Subject: [PATCH 04/21] #19 Demonstrate how to draw an arrow between two images --- .../report/impl/render/DiagramRenderer.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt index 655c7e7..3ae32ac 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -1,7 +1,9 @@ package org.ephyra.acropolis.report.impl.render +import java.awt.BasicStroke import java.awt.Color import java.awt.Graphics2D +import java.awt.Polygon import java.awt.image.BufferedImage import java.awt.image.BufferedImage.TYPE_INT_RGB import java.io.File @@ -31,6 +33,21 @@ class DiagramRenderer( ImageIO.write(targetImg, outFile.extension, outFile) } + fun drawConnection() { + target.stroke = BasicStroke(4f) + target.color = Color.BLUE + target.drawLine(895, 550, 895, 800 - 20) + + target.stroke = BasicStroke(2f) + target.color = Color.YELLOW + val polygon = Polygon() + polygon.addPoint(895, 800) + polygon.addPoint(895 - 20, 800 - 20) + polygon.addPoint(895 + 20, 800 - 20) + target.fill(polygon) + target.drawPolygon(polygon) + } + override fun close() { target.dispose() } From 2d5a2d2be41a609ade57b41456f1f0d8923ee335 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sat, 27 Oct 2018 15:13:32 +0100 Subject: [PATCH 05/21] #19 display text --- .gitignore | 1 + .../report/impl/render/DiagramRenderer.kt | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/.gitignore b/.gitignore index 0edba41..d8d0e13 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ spring-shell.log .idea/* *.log +user diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt index 3ae32ac..efd73a8 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -2,11 +2,13 @@ package org.ephyra.acropolis.report.impl.render import java.awt.BasicStroke import java.awt.Color +import java.awt.Font import java.awt.Graphics2D import java.awt.Polygon import java.awt.image.BufferedImage import java.awt.image.BufferedImage.TYPE_INT_RGB import java.io.File +import java.lang.IllegalStateException import javax.imageio.ImageIO class DiagramRenderer( @@ -48,6 +50,18 @@ class DiagramRenderer( target.drawPolygon(polygon) } + fun drawString(str: String, fontFile: File) { + if (fontFile.extension != "ttf") { + throw IllegalStateException("Cannot use a font which is not TTF") + } + + target.color = Color.DARK_GRAY + var font = Font.createFont(Font.TRUETYPE_FONT, fontFile) + font = font.deriveFont(target.font.size * 2f) + target.font = font + target.drawString(str, 100, 100) + } + override fun close() { target.dispose() } From cc4e857cd7befcde1cb1a81f807104fab37e85e6 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sat, 27 Oct 2018 15:53:00 +0100 Subject: [PATCH 06/21] #19 Build the report model graph in the report service --- .../acropolis/report/api/model/Graph.kt | 13 ++--- .../acropolis/service/impl/ReportService.kt | 49 ++++++++++++++++++- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt index e73a6c5..704567d 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt @@ -26,12 +26,15 @@ class Graph { fun addDirectedEdge(from: Node, to: Node) { edges.add(Edge(from, to, true)) } + + fun findNode(label: String): Node? { + return nodes.find { node -> node.label == label } + } } class Node( val label: String -) { -} +) class Edge( val source: Node, @@ -39,12 +42,10 @@ class Edge( val sink: Node, val directed: Boolean = false -) { -} +) class SubGraphSelector ( val name: String, val includeNodes: List -) { -} +) diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt index a829a93..4685e35 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt @@ -1,13 +1,22 @@ package org.ephyra.acropolis.service.impl +import org.ephyra.acropolis.persistence.api.ConnectionType +import org.ephyra.acropolis.persistence.api.IConnectable +import org.ephyra.acropolis.persistence.api.entity.ApplicationSoftwareEntity +import org.ephyra.acropolis.persistence.api.entity.SystemSoftwareEntity import org.ephyra.acropolis.report.api.IReportRunner +import org.ephyra.acropolis.report.api.model.Graph +import org.ephyra.acropolis.report.api.model.GraphContainer +import org.ephyra.acropolis.report.api.model.Node import org.ephyra.acropolis.service.api.IApplicationSoftwareService +import org.ephyra.acropolis.service.api.IConnectionService import org.ephyra.acropolis.service.api.IReportService import org.ephyra.acropolis.service.api.ISystemSoftwareService import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service +import java.lang.IllegalStateException /** * Report service implementation @@ -22,13 +31,49 @@ class ReportService : IReportService { @Autowired private lateinit var systemService: ISystemSoftwareService + @Autowired + private lateinit var connectionService: IConnectionService + @Autowired private lateinit var reportRunner: IReportRunner override fun runSoftwareReport(projectName: String) { logger.trace("Starting to run software report for project [$projectName]") - applicationService.findAll(projectName) - systemService.findAll(projectName) + val applications = applicationService.findAll(projectName) + val systems = systemService.findAll(projectName) + + val nodeMap: MutableMap = HashMap() + val graph = Graph() + + applications.forEach { app -> + val node = Node(app.name) + graph.addNode(node) + + nodeMap[app] = node + } + + systems.forEach { system -> + val node = Node(system.name) + graph.addNode(node) + + nodeMap[system] = node + } + + nodeMap.forEach { fromConnectable, fromNode -> + val connections = connectionService.getConnectionsFrom(fromConnectable, ConnectionType.TALKS_TO) + connections.forEach { toConnection -> + val toNode = when (toConnection) { + is SystemSoftwareEntity -> graph.findNode(toConnection.name) + is ApplicationSoftwareEntity -> graph.findNode(toConnection.name) + else -> throw IllegalStateException("Unknown connection type type") + } ?: throw IllegalStateException("Unable to find node to connect to") + + graph.addDirectedEdge(fromNode, toNode) + } + } + + val graphContainer = GraphContainer(graph) + reportRunner.run(graphContainer) } } From 2836ca75079d4fe8600bc15e6c353cda953b8f3a Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sat, 27 Oct 2018 23:22:30 +0100 Subject: [PATCH 07/21] #19 building report from graph --- .../acropolis/report/api/model/Graph.kt | 28 ++++++++++++ .../acropolis/report/impl/ReportRunner.kt | 43 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt index 704567d..fc0e096 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt @@ -30,6 +30,34 @@ class Graph { fun findNode(label: String): Node? { return nodes.find { node -> node.label == label } } + + // Only valid for di-graphs, otherwise much allow edges if incoming edges have a corresponding outgoing edge. + fun findSourceNodes(): HashSet { + val tempNodes = HashSet() + tempNodes.addAll(nodes) + + edges.forEach { edge -> + val node = edge.sink + tempNodes.remove(node) + } + + return tempNodes + } + + fun firstNode(): Node { + return nodes.first() + } + + fun findNodesConnectedFrom(node: Node): HashSet { + val tempNodes = HashSet() + edges.forEach { edge -> + if (edge.source == node) { + tempNodes.add(edge.sink) + } + } + + return tempNodes + } } class Node( diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 78eafd3..1e62973 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -1,12 +1,55 @@ package org.ephyra.acropolis.report.impl import org.ephyra.acropolis.report.api.IReportRunner +import org.ephyra.acropolis.report.api.model.Graph import org.ephyra.acropolis.report.api.model.GraphContainer +import org.ephyra.acropolis.report.api.model.Node import org.springframework.stereotype.Component @Component private class ReportRunner : IReportRunner { override fun run(graphContainer: GraphContainer) { println("Running report") + buildNodeDepth(graphContainer.graph) + + + } + + fun buildNodeDepth(graph: Graph): HashMap { + val startNode = pickStartNode(graph) + + val depths = HashMap() + depths[startNode] = 0 + + nodeDepth(startNode, graph, depths, 1) + + return depths + } + + fun nodeDepth(currentNode: Node, graph: Graph, depths: HashMap, depth: Int) { + val connected = graph.findNodesConnectedFrom(currentNode) + + // Remove all the nodes which are already numbered. + connected.removeAll(depths.keys) + + // Number each of the connected nodes. + connected.forEach { con -> + depths[con] = depth + } + + // Now apply the same process to each of the nodes we just numbered. + connected.forEach { con -> + nodeDepth(con, graph, depths, depth + 1) + } + } + + fun pickStartNode(graph: Graph): Node { + val sourceNodes = graph.findSourceNodes() + return if (sourceNodes.isEmpty()) { + graph.firstNode() + } + else { + sourceNodes.first() + } } } From 89e70d7af8af1284e15fc1fb94b58a5476b01bbd Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sun, 28 Oct 2018 23:23:04 +0000 Subject: [PATCH 08/21] #19 start working on the layout process --- .../acropolis/report/impl/ReportRunner.kt | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 1e62973..28d5fb9 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -4,15 +4,47 @@ import org.ephyra.acropolis.report.api.IReportRunner import org.ephyra.acropolis.report.api.model.Graph import org.ephyra.acropolis.report.api.model.GraphContainer import org.ephyra.acropolis.report.api.model.Node +import org.ephyra.acropolis.report.impl.render.DiagramRenderer import org.springframework.stereotype.Component +import java.lang.IllegalStateException @Component private class ReportRunner : IReportRunner { override fun run(graphContainer: GraphContainer) { println("Running report") - buildNodeDepth(graphContainer.graph) + val depthMap = buildNodeDepth(graphContainer.graph) + val depthCounts = countDepths(depthMap) - + val maxDepth = depthMap.values.max() ?: throw IllegalStateException("missing depth") + val maxCountAtDepth = depthCounts.values.max() ?: throw IllegalStateException("missing count") + + val tileWidth = 300 + val tileHeight = 350 + + val cardSeparationHorizontal = 75 + val cardSeparationVertical = 35 + + val diagramPadding = 30 + + val diagramWidth = 2 * diagramPadding + (maxDepth + 1) * tileWidth + maxDepth * cardSeparationHorizontal + val diagramHeight = 2 * diagramPadding + (maxCountAtDepth + 1) * tileHeight + maxCountAtDepth * cardSeparationVertical + + DiagramRenderer(diagramWidth, diagramHeight).use { renderer -> + + } + } + + private fun countDepths(depthMap: HashMap): HashMap { + val depthCounts = HashMap() + depthMap.forEach { (_, v) -> + val t = depthCounts[v] + if (t == null) { + depthCounts[v] = 0 + } else { + depthCounts[v] = t + 1 + } + } + return depthCounts } fun buildNodeDepth(graph: Graph): HashMap { @@ -53,3 +85,8 @@ private class ReportRunner : IReportRunner { } } } + +class Position( + val x: Float, + val y: Float +) From 7797d6fdbfe2ff222d97220efbb93a2c249728ad Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Mon, 29 Oct 2018 19:56:58 +0000 Subject: [PATCH 09/21] #19 calculate tile positions --- .../acropolis/report/impl/ReportRunner.kt | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 28d5fb9..3d7a340 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -29,8 +29,31 @@ private class ReportRunner : IReportRunner { val diagramWidth = 2 * diagramPadding + (maxDepth + 1) * tileWidth + maxDepth * cardSeparationHorizontal val diagramHeight = 2 * diagramPadding + (maxCountAtDepth + 1) * tileHeight + maxCountAtDepth * cardSeparationVertical - DiagramRenderer(diagramWidth, diagramHeight).use { renderer -> + val tempDepthCounts = HashMap() + depthCounts.forEach { depth, count -> + tempDepthCounts[depth] = count + } + + val positions = HashMap() + depthMap.forEach { node, depth -> + val currentDepthCount = tempDepthCounts[depth] ?: throw IllegalStateException("missing temp depth count") + + val depthCount = depthCounts[depth] ?: throw IllegalStateException("missing depth count") + + val y = ((diagramHeight - 2 * diagramPadding) / depthCount) * currentDepthCount + diagramPadding - 0.5 * diagramHeight + val position = Position( + (diagramPadding + depth * cardSeparationHorizontal + depth * tileWidth).toFloat(), + y.toFloat() + ) + + positions[node] = position + + tempDepthCounts[depth] = currentDepthCount - 1 + } + + DiagramRenderer(diagramWidth, diagramHeight).use { renderer -> + } } From 548989cdbacf40938bac9727b914c2254493f2d4 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 30 Oct 2018 00:39:21 +0000 Subject: [PATCH 10/21] #19 Give the report service access to the graphical asset service --- .../persistence/GraphicalAssetPersistence.kt | 5 +++++ .../impl/GraphicalAssetRepository.kt | 5 ++++- .../acropolis/report/api/IImageSource.kt | 7 +++++++ .../acropolis/report/api/IReportRunner.kt | 2 +- .../acropolis/report/impl/ReportRunner.kt | 5 +++-- .../service/api/IGraphicalAssetService.kt | 3 +++ .../service/impl/GraphicalAssetImageSource.kt | 21 +++++++++++++++++++ .../service/impl/GraphicalAssetService.kt | 4 ++++ .../acropolis/service/impl/ReportService.kt | 5 ++++- 9 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt create mode 100644 acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt diff --git a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt index 03ace06..38c8a0b 100644 --- a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt +++ b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt @@ -30,4 +30,9 @@ class GraphicalAssetPersistence { fun findAll(): MutableIterable { return repo.findAll() } + + fun find(name: String): GraphicalAssetEntity? { + val asset = repo.findByName(name) + return if (asset.isPresent) asset.get() else null + } } diff --git a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt index 3f31ea9..7f50572 100644 --- a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt +++ b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt @@ -2,8 +2,11 @@ package org.ephyra.acropolis.persistence.impl import org.ephyra.acropolis.persistence.api.entity.GraphicalAssetEntity import org.springframework.data.repository.CrudRepository +import java.util.Optional /** * Repository for storing graphical assets */ -interface GraphicalAssetRepository : CrudRepository +interface GraphicalAssetRepository : CrudRepository { + fun findByName(name: String): Optional +} diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt new file mode 100644 index 0000000..26fc716 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt @@ -0,0 +1,7 @@ +package org.ephyra.acropolis.report.api + +import java.io.InputStream + +interface IImageSource { + fun get(resourceName: String): InputStream +} diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt index 6aa8589..e2bf131 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt @@ -3,5 +3,5 @@ package org.ephyra.acropolis.report.api import org.ephyra.acropolis.report.api.model.GraphContainer interface IReportRunner { - fun run(graphContainer: GraphContainer) + fun run(graphContainer: GraphContainer, imageSource: IImageSource) } diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 3d7a340..3c5b194 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -1,5 +1,6 @@ package org.ephyra.acropolis.report.impl +import org.ephyra.acropolis.report.api.IImageSource import org.ephyra.acropolis.report.api.IReportRunner import org.ephyra.acropolis.report.api.model.Graph import org.ephyra.acropolis.report.api.model.GraphContainer @@ -10,7 +11,7 @@ import java.lang.IllegalStateException @Component private class ReportRunner : IReportRunner { - override fun run(graphContainer: GraphContainer) { + override fun run(graphContainer: GraphContainer, imageSource: IImageSource) { println("Running report") val depthMap = buildNodeDepth(graphContainer.graph) val depthCounts = countDepths(depthMap) @@ -53,7 +54,7 @@ private class ReportRunner : IReportRunner { } DiagramRenderer(diagramWidth, diagramHeight).use { renderer -> - + } } diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt index c5f0b77..7315560 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt @@ -1,6 +1,7 @@ package org.ephyra.acropolis.service.api import org.ephyra.acropolis.persistence.api.GraphicalAssetType +import org.ephyra.acropolis.persistence.api.entity.GraphicalAssetEntity import org.ephyra.acropolis.service.api.model.GraphicalAsset /** @@ -22,4 +23,6 @@ interface IGraphicalAssetService { * @return list of graphical assets */ fun findAll(): List + + fun find(name: String): GraphicalAssetEntity? } diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt new file mode 100644 index 0000000..602f8ba --- /dev/null +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt @@ -0,0 +1,21 @@ +package org.ephyra.acropolis.service.impl + +import org.ephyra.acropolis.report.api.IImageSource +import org.ephyra.acropolis.service.api.IGraphicalAssetService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import java.io.ByteArrayInputStream +import java.io.InputStream +import java.lang.IllegalStateException + +@Component +class GraphicalAssetImageSource : IImageSource { + @Autowired + private lateinit var graphicalAssetService: IGraphicalAssetService + + override fun get(resourceName: String): InputStream { + val asset = graphicalAssetService.find(resourceName) + ?: throw IllegalStateException("Missing resource [$resourceName]") + return ByteArrayInputStream(asset.source) + } +} diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetService.kt index 8042d99..ef208a1 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetService.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetService.kt @@ -32,4 +32,8 @@ class GraphicalAssetService : IGraphicalAssetService { GraphicalAsset(type, assetEntity.source) } } + + override fun find(name: String): GraphicalAssetEntity? { + return persistence.find(name) + } } diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt index 4685e35..c8cb226 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt @@ -37,6 +37,9 @@ class ReportService : IReportService { @Autowired private lateinit var reportRunner: IReportRunner + @Autowired + private lateinit var graphicalAssetImageSource: GraphicalAssetImageSource + override fun runSoftwareReport(projectName: String) { logger.trace("Starting to run software report for project [$projectName]") @@ -74,6 +77,6 @@ class ReportService : IReportService { } val graphContainer = GraphContainer(graph) - reportRunner.run(graphContainer) + reportRunner.run(graphContainer, graphicalAssetImageSource) } } From f01f3f8c1b3de7a20445662df86fabf90a192008 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 30 Oct 2018 20:28:26 +0000 Subject: [PATCH 11/21] #19 fix detekt issues and add docs --- .../persistence/GraphicalAssetPersistence.kt | 6 ++ .../impl/GraphicalAssetRepository.kt | 6 ++ .../acropolis/report/api/IImageSource.kt | 9 +++ .../acropolis/report/api/IReportRunner.kt | 9 +++ .../acropolis/report/api/model/Graph.kt | 61 ++++++++++++++++++- .../report/config/ReportConfiguration.kt | 4 ++ .../acropolis/report/impl/ReportRunner.kt | 15 ++++- .../report/impl/render/DiagramRenderer.kt | 26 ++++++++ .../service/api/IGraphicalAssetService.kt | 6 ++ .../service/config/ServiceConfiguration.kt | 6 +- .../service/impl/GraphicalAssetImageSource.kt | 4 ++ 11 files changed, 147 insertions(+), 5 deletions(-) diff --git a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt index 38c8a0b..508a94f 100644 --- a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt +++ b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/api/persistence/GraphicalAssetPersistence.kt @@ -31,6 +31,12 @@ class GraphicalAssetPersistence { return repo.findAll() } + /** + * Find a graphical asset by name + * + * @param name The name of the asset + * @return the asset, if found + */ fun find(name: String): GraphicalAssetEntity? { val asset = repo.findByName(name) return if (asset.isPresent) asset.get() else null diff --git a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt index 7f50572..094f620 100644 --- a/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt +++ b/acropolis-persistence/src/main/kotlin/org/ephyra/acropolis/persistence/impl/GraphicalAssetRepository.kt @@ -8,5 +8,11 @@ import java.util.Optional * Repository for storing graphical assets */ interface GraphicalAssetRepository : CrudRepository { + /** + * Find a graphical asset by name + * + * @param name The name of the asset + * @return the asset, if found + */ fun findByName(name: String): Optional } diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt index 26fc716..4832a88 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IImageSource.kt @@ -2,6 +2,15 @@ package org.ephyra.acropolis.report.api import java.io.InputStream +/** + * Image source to provide images on request to the rendering process. + */ interface IImageSource { + /** + * Get an image by its resource name + * + * @param resourceName The resource name of the image + * @return An input stream for the image data to be read from + */ fun get(resourceName: String): InputStream } diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt index e2bf131..cfaa22b 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/IReportRunner.kt @@ -2,6 +2,15 @@ package org.ephyra.acropolis.report.api import org.ephyra.acropolis.report.api.model.GraphContainer +/** + * Interface for a report runner. This interface provides the entry point into this module. + */ interface IReportRunner { + /** + * Run a report based on the provided model + * + * @param graphContainer The container for the model to build the report from + * @param imageSource Source to allow images to be provided during the rendering process + */ fun run(graphContainer: GraphContainer, imageSource: IImageSource) } diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt index fc0e096..222dad1 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt @@ -1,37 +1,78 @@ package org.ephyra.acropolis.report.api.model +/** + * Container for a graph model. + * Allows metadata to be provided with the model. + */ class GraphContainer( val graph: Graph ) { private val subGraphs: MutableList = ArrayList() + /** + * Define a named sub-graph of the graph held by this container. + * The provided list of nodes can later be used to extract a sub-graph. + * + * @param name The name of the sub-graph + * @param includeNodes The nodes to include in the sub-graph + */ fun defineSubgraph(name: String, includeNodes: List) { subGraphs.add(SubGraphSelector(name, includeNodes)) } } +/** + * Model to represent a graph, in the mathematical sense. + */ class Graph { private val nodes: MutableSet = HashSet() private val edges: MutableList = ArrayList() + /** + * Add a node to the graph + * + * @param node The node to add + */ fun addNode(node: Node) { nodes.add(node) } + /** + * Add an edge between two nodes + * + * @param n1 Node to connect + * @param n2 Node to connect + */ fun addEdge(n1: Node, n2: Node) { edges.add(Edge(n1, n2, false)) } + /** + * Add a directed edge between two nodes + * + * @param from The source node for the edge + * @param to The sink node for the edge + */ fun addDirectedEdge(from: Node, to: Node) { edges.add(Edge(from, to, true)) } + /** + * Find a node by its label + * + * @param label The label to search for + * @return The node, if found + */ fun findNode(label: String): Node? { return nodes.find { node -> node.label == label } } - // Only valid for di-graphs, otherwise much allow edges if incoming edges have a corresponding outgoing edge. + /** + * Find nodes, N, such that all edges which connect N to the graph, N is the source. + * + * Only valid for di-graphs, otherwise must allow edges if incoming edges have a corresponding outgoing edge. + */ fun findSourceNodes(): HashSet { val tempNodes = HashSet() tempNodes.addAll(nodes) @@ -44,10 +85,19 @@ class Graph { return tempNodes } + /** + * Return which ever node happens to be first. + * + * @return The first node in the graph, as it is stored + */ fun firstNode(): Node { return nodes.first() } + /** + * Finds edges such that the specified node is the source, and collects the set of sink nodes + * from these edges. + */ fun findNodesConnectedFrom(node: Node): HashSet { val tempNodes = HashSet() edges.forEach { edge -> @@ -60,10 +110,16 @@ class Graph { } } +/** + * Model to represent a node in a graph + */ class Node( val label: String ) +/** + * Model to represent an edge in a graph + */ class Edge( val source: Node, @@ -72,6 +128,9 @@ class Edge( val directed: Boolean = false ) +/** + * Selector for building a sub-graph from a subset of a graph's nodes. + */ class SubGraphSelector ( val name: String, diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt index 1f3c6e8..a434dda 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/config/ReportConfiguration.kt @@ -3,6 +3,10 @@ package org.ephyra.acropolis.report.config import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration +/** + * Configuration root for the module. By directing the Spring framework to load this class as configuration + * the entire module will be configured for use. + */ @Configuration @ComponentScan(basePackages = ["org.ephyra.acropolis.report.config", "org.ephyra.acropolis.report.impl"]) open class ReportConfiguration diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 3c5b194..bc492ef 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -9,8 +9,12 @@ import org.ephyra.acropolis.report.impl.render.DiagramRenderer import org.springframework.stereotype.Component import java.lang.IllegalStateException +/** + * Implementation of the report runner interface. + */ +@Suppress("MagicNumber") @Component -private class ReportRunner : IReportRunner { +internal class ReportRunner : IReportRunner { override fun run(graphContainer: GraphContainer, imageSource: IImageSource) { println("Running report") val depthMap = buildNodeDepth(graphContainer.graph) @@ -28,7 +32,8 @@ private class ReportRunner : IReportRunner { val diagramPadding = 30 val diagramWidth = 2 * diagramPadding + (maxDepth + 1) * tileWidth + maxDepth * cardSeparationHorizontal - val diagramHeight = 2 * diagramPadding + (maxCountAtDepth + 1) * tileHeight + maxCountAtDepth * cardSeparationVertical + val diagramHeight = 2 * diagramPadding + (maxCountAtDepth + 1) * tileHeight + + maxCountAtDepth * cardSeparationVertical val tempDepthCounts = HashMap() depthCounts.forEach { depth, count -> @@ -41,7 +46,8 @@ private class ReportRunner : IReportRunner { val depthCount = depthCounts[depth] ?: throw IllegalStateException("missing depth count") - val y = ((diagramHeight - 2 * diagramPadding) / depthCount) * currentDepthCount + diagramPadding - 0.5 * diagramHeight + val y = ((diagramHeight - 2 * diagramPadding) / depthCount) * currentDepthCount + + diagramPadding - 0.5 * diagramHeight val position = Position( (diagramPadding + depth * cardSeparationHorizontal + depth * tileWidth).toFloat(), @@ -110,6 +116,9 @@ private class ReportRunner : IReportRunner { } } +/** + * Represents a position on a 2D plane + */ class Position( val x: Float, val y: Float diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt index efd73a8..2f1b2d5 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -11,6 +11,11 @@ import java.io.File import java.lang.IllegalStateException import javax.imageio.ImageIO +/** + * Wrapper around Java2D API operations to provide a specific set of operations for use + * in diagram rendering. + */ +@Suppress("MagicNumber") class DiagramRenderer( private val width: Int, @@ -26,15 +31,30 @@ class DiagramRenderer( target.fillRect(0, 0, width, height) } + /** + * Add an image to the diagram at the specified coordinates + * + * @param positionX The offset of the left side of the image from the left side of the diagram + * @param positionY The offset of the top side of the image from the top side of the diagram + * @param source The source to fetch the image from + */ fun addImage(positionX: Int, positionY: Int, source: File) { val img = ImageIO.read(source) target.drawImage(img, positionX, positionY, img.width, img.height, null) } + /** + * Export the diagram to file + * + * @param outFile The file to write to + */ fun export(outFile: File) { ImageIO.write(targetImg, outFile.extension, outFile) } + /** + * Draw a connection between two tiles. + */ fun drawConnection() { target.stroke = BasicStroke(4f) target.color = Color.BLUE @@ -50,6 +70,12 @@ class DiagramRenderer( target.drawPolygon(polygon) } + /** + * Draw a string of text onto the diagram using the given font. + * + * @param str The text to draw + * @param fontFile The file from which to load a font for use in the rendering + */ fun drawString(str: String, fontFile: File) { if (fontFile.extension != "ttf") { throw IllegalStateException("Cannot use a font which is not TTF") diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt index 7315560..d97577f 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/api/IGraphicalAssetService.kt @@ -24,5 +24,11 @@ interface IGraphicalAssetService { */ fun findAll(): List + /** + * Find a graphical asset by name + * + * @param name The name of the asset to find + * @return The graphical asset, if found + */ fun find(name: String): GraphicalAssetEntity? } diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt index e582c64..3b56ac4 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/config/ServiceConfiguration.kt @@ -8,5 +8,9 @@ import org.springframework.context.annotation.Configuration * in order to configure this module correctly. */ @Configuration -@ComponentScan(basePackages = ["org.ephyra.acropolis.persistence.config", "org.ephyra.acropolis.report.config", "org.ephyra.acropolis.service.impl"]) +@ComponentScan(basePackages = [ + "org.ephyra.acropolis.persistence.config", + "org.ephyra.acropolis.report.config", + "org.ephyra.acropolis.service.impl" +]) class ServiceConfiguration diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt index 602f8ba..e3c6034 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/GraphicalAssetImageSource.kt @@ -8,6 +8,10 @@ import java.io.ByteArrayInputStream import java.io.InputStream import java.lang.IllegalStateException +/** + * Implementation of the image source for use with the report module. + * The implementation makes use of the graphical asset service to load requested resources from the database. + */ @Component class GraphicalAssetImageSource : IImageSource { @Autowired From 5ab3d48fcf0782a77d6b56e7749816b65f71abc8 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sat, 10 Nov 2018 22:03:29 +0000 Subject: [PATCH 12/21] #19 Draw images onto the report --- .../acropolis/report/api/model/Graph.kt | 4 ++- .../acropolis/report/impl/ReportRunner.kt | 5 +++- .../report/impl/render/DiagramRenderer.kt | 5 ++-- .../acropolis/service/impl/ReportService.kt | 30 +++++++++++++++++-- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt index 222dad1..0d61e4e 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/api/model/Graph.kt @@ -114,7 +114,9 @@ class Graph { * Model to represent a node in a graph */ class Node( - val label: String + val label: String, + + val representedByResourceName: String ) /** diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index bc492ef..55cd5b9 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -60,7 +60,10 @@ internal class ReportRunner : IReportRunner { } DiagramRenderer(diagramWidth, diagramHeight).use { renderer -> - + positions.forEach { node, position -> + val imageResource = imageSource.get(node.representedByResourceName) + renderer.addImage(position.x.toInt(), position.y.toInt(), imageResource) + } } } diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt index 2f1b2d5..be23111 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -8,6 +8,7 @@ import java.awt.Polygon import java.awt.image.BufferedImage import java.awt.image.BufferedImage.TYPE_INT_RGB import java.io.File +import java.io.InputStream import java.lang.IllegalStateException import javax.imageio.ImageIO @@ -36,9 +37,9 @@ class DiagramRenderer( * * @param positionX The offset of the left side of the image from the left side of the diagram * @param positionY The offset of the top side of the image from the top side of the diagram - * @param source The source to fetch the image from + * @param source The input stream to read the image from */ - fun addImage(positionX: Int, positionY: Int, source: File) { + fun addImage(positionX: Int, positionY: Int, source: InputStream) { val img = ImageIO.read(source) target.drawImage(img, positionX, positionY, img.width, img.height, null) } diff --git a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt index c8cb226..f46b253 100644 --- a/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt +++ b/acropolis-service/src/main/kotlin/org/ephyra/acropolis/service/impl/ReportService.kt @@ -1,8 +1,14 @@ package org.ephyra.acropolis.service.impl +import org.ephyra.acropolis.external.SystemSoftwareSpecialization +import org.ephyra.acropolis.external.packSystemSpecialization import org.ephyra.acropolis.persistence.api.ConnectionType import org.ephyra.acropolis.persistence.api.IConnectable import org.ephyra.acropolis.persistence.api.entity.ApplicationSoftwareEntity +import org.ephyra.acropolis.persistence.api.entity.DatastoreEntity +import org.ephyra.acropolis.persistence.api.entity.LoadBalancerEntity +import org.ephyra.acropolis.persistence.api.entity.QueueEntity +import org.ephyra.acropolis.persistence.api.entity.ReverseProxyEntity import org.ephyra.acropolis.persistence.api.entity.SystemSoftwareEntity import org.ephyra.acropolis.report.api.IReportRunner import org.ephyra.acropolis.report.api.model.Graph @@ -50,14 +56,14 @@ class ReportService : IReportService { val graph = Graph() applications.forEach { app -> - val node = Node(app.name) + val node = Node(app.name, "application") graph.addNode(node) nodeMap[app] = node } systems.forEach { system -> - val node = Node(system.name) + val node = Node(system.name, getRepresentedByResourceNameFromSystem(system)) graph.addNode(node) nodeMap[system] = node @@ -79,4 +85,24 @@ class ReportService : IReportService { val graphContainer = GraphContainer(graph) reportRunner.run(graphContainer, graphicalAssetImageSource) } + + /** + * Gets the default image resource name for a given system. Falls back to the + * default resource names. + */ + private fun getRepresentedByResourceNameFromSystem(system: SystemSoftwareEntity): String { + // TODO this is bootstrap data and should be extracted. + return if (system.specialization == null) { + "system" + } + else { + when (system.specialization) { + is LoadBalancerEntity -> "load-balancer" + is DatastoreEntity -> "datastore" + is QueueEntity -> "queue" + is ReverseProxyEntity -> "reverse-proxy" + else -> "system" + } + } + } } From eaea7547575048e4114c0084da3d17140223bd43 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sun, 11 Nov 2018 00:57:44 +0000 Subject: [PATCH 13/21] #19 Create default images for software specializations --- .gitignore | 2 +- user/graphics/datastore.png | Bin 0 -> 35988 bytes user/graphics/datastore.svg | 98 +++++++++++++++++++++++ user/graphics/load-balancer.png | Bin 0 -> 5089 bytes user/graphics/load-balancer.svg | 112 ++++++++++++++++++++++++++ user/graphics/queue.png | Bin 0 -> 52273 bytes user/graphics/queue.svg | 135 ++++++++++++++++++++++++++++++++ user/graphics/reverse-proxy.png | Bin 0 -> 5089 bytes user/graphics/reverse-proxy.svg | 112 ++++++++++++++++++++++++++ 9 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 user/graphics/datastore.png create mode 100644 user/graphics/datastore.svg create mode 100644 user/graphics/load-balancer.png create mode 100644 user/graphics/load-balancer.svg create mode 100644 user/graphics/queue.png create mode 100644 user/graphics/queue.svg create mode 100644 user/graphics/reverse-proxy.png create mode 100644 user/graphics/reverse-proxy.svg diff --git a/.gitignore b/.gitignore index d8d0e13..4cba755 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,4 @@ spring-shell.log .idea/* *.log -user +user/staging diff --git a/user/graphics/datastore.png b/user/graphics/datastore.png new file mode 100644 index 0000000000000000000000000000000000000000..41b90d5bfe53569205020a7eb59c33258c0027a0 GIT binary patch literal 35988 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

#K_BrJx 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 JzgD*n|6ks(m`eZv literal 0 HcmV?d00001 diff --git a/user/graphics/datastore.svg b/user/graphics/datastore.svg new file mode 100644 index 0000000..33a1883 --- /dev/null +++ b/user/graphics/datastore.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/user/graphics/load-balancer.png b/user/graphics/load-balancer.png new file mode 100644 index 0000000000000000000000000000000000000000..e7cd1979baae60dbcd2e89a1c9ac76bd8c859fe9 GIT binary patch literal 5089 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 literal 0 HcmV?d00001 diff --git a/user/graphics/load-balancer.svg b/user/graphics/load-balancer.svg new file mode 100644 index 0000000..e30832f --- /dev/null +++ b/user/graphics/load-balancer.svg @@ -0,0 +1,112 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/user/graphics/queue.png b/user/graphics/queue.png new file mode 100644 index 0000000000000000000000000000000000000000..f647e74311b3e99df5f0197e2721624ca95431b5 GIT binary patch literal 52273 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 t2!Bon|6 + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/user/graphics/reverse-proxy.png b/user/graphics/reverse-proxy.png new file mode 100644 index 0000000000000000000000000000000000000000..e7cd1979baae60dbcd2e89a1c9ac76bd8c859fe9 GIT binary patch literal 5089 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 literal 0 HcmV?d00001 diff --git a/user/graphics/reverse-proxy.svg b/user/graphics/reverse-proxy.svg new file mode 100644 index 0000000..80822fc --- /dev/null +++ b/user/graphics/reverse-proxy.svg @@ -0,0 +1,112 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + From 37e0e296da94ad6c8a56dcb353afaf0c5e23a92b Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sun, 11 Nov 2018 15:29:42 +0000 Subject: [PATCH 14/21] #19 create application and system graphics and bootstrap command --- .../acropolis/shell/BootstrapCommand.kt | 63 ++++++++++++ user/graphics/application.png | Bin 0 -> 49614 bytes user/graphics/application.svg | 95 ++++++++++++++++++ user/graphics/system.png | Bin 0 -> 70276 bytes user/graphics/system.svg | 92 +++++++++++++++++ 5 files changed, 250 insertions(+) create mode 100644 acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt create mode 100644 user/graphics/application.png create mode 100644 user/graphics/application.svg create mode 100644 user/graphics/system.png create mode 100644 user/graphics/system.svg diff --git a/acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt b/acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt new file mode 100644 index 0000000..535b08a --- /dev/null +++ b/acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt @@ -0,0 +1,63 @@ +package org.ephyra.acropolis.shell + +import org.ephyra.acropolis.persistence.api.GraphicalAssetType +import org.ephyra.acropolis.service.api.IGraphicalAssetService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.shell.standard.ShellComponent +import org.springframework.shell.standard.ShellMethod +import java.io.File + +@ShellComponent +class BootstrapCommand { + @Autowired + private lateinit var graphicalAssetService: IGraphicalAssetService + + @ShellMethod("Bootstrap Acropolis") + fun bootstrap() { + println("Bootstrapping the acropolis system.") + + importGraphicalAssets() + + println("Done. Acropolis is now ready to use!") + } + + private fun importGraphicalAssets() { + println("Importing graphical assets") + + graphicalAssetService.create( + "load-balancer", + File("user/graphics/load-balancer.png").readBytes(), + GraphicalAssetType.PNG + ) + + graphicalAssetService.create( + "reverse-proxy", + File("user/graphics/reverse-proxy.png").readBytes(), + GraphicalAssetType.PNG + ) + + graphicalAssetService.create( + "queue", + File("user/graphics/queue.png").readBytes(), + GraphicalAssetType.PNG + ) + + graphicalAssetService.create( + "datastore", + File("user/graphics/datastore.png").readBytes(), + GraphicalAssetType.PNG + ) + + graphicalAssetService.create( + "application", + File("user/graphics/application.png").readBytes(), + GraphicalAssetType.PNG + ) + + graphicalAssetService.create( + "system", + File("user/graphics/system.png").readBytes(), + GraphicalAssetType.PNG + ) + } +} \ No newline at end of file diff --git a/user/graphics/application.png b/user/graphics/application.png new file mode 100644 index 0000000000000000000000000000000000000000..c99aaa88be15c80b8b13d0ee709486056001a573 GIT binary patch literal 49614 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

s%(s_xg7` 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 + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/user/graphics/system.png b/user/graphics/system.png new file mode 100644 index 0000000000000000000000000000000000000000..03b6ce05b437aadbb089088bd431f4f823d96538 GIT binary patch literal 70276 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 literal 0 HcmV?d00001 diff --git a/user/graphics/system.svg b/user/graphics/system.svg new file mode 100644 index 0000000..7651c51 --- /dev/null +++ b/user/graphics/system.svg @@ -0,0 +1,92 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + From 5b3efe945cef0c7f84da56967ea0fde95adf331d Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sun, 11 Nov 2018 20:22:10 +0000 Subject: [PATCH 15/21] #19 Bug fix for depth counts and export after report run --- .../kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 55cd5b9..4c7533c 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -7,6 +7,7 @@ import org.ephyra.acropolis.report.api.model.GraphContainer import org.ephyra.acropolis.report.api.model.Node import org.ephyra.acropolis.report.impl.render.DiagramRenderer import org.springframework.stereotype.Component +import java.io.File import java.lang.IllegalStateException /** @@ -64,6 +65,7 @@ internal class ReportRunner : IReportRunner { val imageResource = imageSource.get(node.representedByResourceName) renderer.addImage(position.x.toInt(), position.y.toInt(), imageResource) } + renderer.export(File("test-report.png")) } } @@ -72,7 +74,7 @@ internal class ReportRunner : IReportRunner { depthMap.forEach { (_, v) -> val t = depthCounts[v] if (t == null) { - depthCounts[v] = 0 + depthCounts[v] = 1 } else { depthCounts[v] = t + 1 } From 0e79762c43a7522f11a21f439aa93ffb3ac88452 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Sun, 11 Nov 2018 21:23:07 +0000 Subject: [PATCH 16/21] #19 Fixes for positioning --- .../acropolis/report/impl/ReportRunner.kt | 21 ++++++++++++------- .../report/impl/render/DiagramRenderer.kt | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 4c7533c..29165db 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -6,6 +6,7 @@ import org.ephyra.acropolis.report.api.model.Graph import org.ephyra.acropolis.report.api.model.GraphContainer import org.ephyra.acropolis.report.api.model.Node import org.ephyra.acropolis.report.impl.render.DiagramRenderer +import org.slf4j.LoggerFactory import org.springframework.stereotype.Component import java.io.File import java.lang.IllegalStateException @@ -16,13 +17,15 @@ import java.lang.IllegalStateException @Suppress("MagicNumber") @Component internal class ReportRunner : IReportRunner { + private val logger = LoggerFactory.getLogger(ReportRunner::class.java) + override fun run(graphContainer: GraphContainer, imageSource: IImageSource) { println("Running report") val depthMap = buildNodeDepth(graphContainer.graph) val depthCounts = countDepths(depthMap) val maxDepth = depthMap.values.max() ?: throw IllegalStateException("missing depth") - val maxCountAtDepth = depthCounts.values.max() ?: throw IllegalStateException("missing count") + val maxDepthCount = depthCounts.values.max() ?: throw IllegalStateException("missing count") val tileWidth = 300 val tileHeight = 350 @@ -33,8 +36,10 @@ internal class ReportRunner : IReportRunner { val diagramPadding = 30 val diagramWidth = 2 * diagramPadding + (maxDepth + 1) * tileWidth + maxDepth * cardSeparationHorizontal - val diagramHeight = 2 * diagramPadding + (maxCountAtDepth + 1) * tileHeight - + maxCountAtDepth * cardSeparationVertical + val diagramHeight = 2 * diagramPadding + maxDepthCount * tileHeight + + (maxDepthCount - 1) * cardSeparationVertical + + logger.debug("Creating diagram with dimensions [w=$diagramWidth, h=$diagramHeight]") val tempDepthCounts = HashMap() depthCounts.forEach { depth, count -> @@ -45,16 +50,18 @@ internal class ReportRunner : IReportRunner { depthMap.forEach { node, depth -> val currentDepthCount = tempDepthCounts[depth] ?: throw IllegalStateException("missing temp depth count") - val depthCount = depthCounts[depth] ?: throw IllegalStateException("missing depth count") + val x = diagramPadding + depth * cardSeparationHorizontal + depth * tileWidth - val y = ((diagramHeight - 2 * diagramPadding) / depthCount) * currentDepthCount - + diagramPadding - 0.5 * diagramHeight + val y = diagramPadding + (currentDepthCount - 1) * tileHeight + + (currentDepthCount - 1) * cardSeparationVertical val position = Position( - (diagramPadding + depth * cardSeparationHorizontal + depth * tileWidth).toFloat(), + x.toFloat(), y.toFloat() ) + logger.debug("Placing node [label=${node.label}] at position [x=$x, y=$y") + positions[node] = position tempDepthCounts[depth] = currentDepthCount - 1 diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt index be23111..55aa1ae 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -41,7 +41,7 @@ class DiagramRenderer( */ fun addImage(positionX: Int, positionY: Int, source: InputStream) { val img = ImageIO.read(source) - target.drawImage(img, positionX, positionY, img.width, img.height, null) + target.drawImage(img, positionX, positionY, 300, 350, null) } /** From d4839eabd2eece1971674981ee8f692ddb39f88e Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Mon, 12 Nov 2018 00:01:56 +0000 Subject: [PATCH 17/21] #19 Start on card builder for rendering images with text --- .../acropolis/report/impl/ReportRunner.kt | 20 +++++++------- .../report/impl/render/CardBuilder.kt | 26 +++++++++++++++++++ .../report/impl/render/Position2D.kt | 9 +++++++ .../acropolis/report/impl/render/Size2D.kt | 6 +++++ 4 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt create mode 100644 acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 29165db..e815361 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -5,7 +5,10 @@ import org.ephyra.acropolis.report.api.IReportRunner import org.ephyra.acropolis.report.api.model.Graph import org.ephyra.acropolis.report.api.model.GraphContainer import org.ephyra.acropolis.report.api.model.Node +import org.ephyra.acropolis.report.impl.render.CardBuilder import org.ephyra.acropolis.report.impl.render.DiagramRenderer +import org.ephyra.acropolis.report.impl.render.Position2D +import org.ephyra.acropolis.report.impl.render.Size2D import org.slf4j.LoggerFactory import org.springframework.stereotype.Component import java.io.File @@ -46,7 +49,7 @@ internal class ReportRunner : IReportRunner { tempDepthCounts[depth] = count } - val positions = HashMap() + val positions = HashMap() depthMap.forEach { node, depth -> val currentDepthCount = tempDepthCounts[depth] ?: throw IllegalStateException("missing temp depth count") @@ -55,7 +58,7 @@ internal class ReportRunner : IReportRunner { val y = diagramPadding + (currentDepthCount - 1) * tileHeight + (currentDepthCount - 1) * cardSeparationVertical - val position = Position( + val position = Position2D( x.toFloat(), y.toFloat() ) @@ -69,6 +72,11 @@ internal class ReportRunner : IReportRunner { DiagramRenderer(diagramWidth, diagramHeight).use { renderer -> positions.forEach { node, position -> + CardBuilder(position, Size2D(tileWidth.toFloat(), tileHeight.toFloat())) + .withImage(imageSource.get(node.representedByResourceName)) + .withLabel(node.label) + .build(renderer) + val imageResource = imageSource.get(node.representedByResourceName) renderer.addImage(position.x.toInt(), position.y.toInt(), imageResource) } @@ -127,11 +135,3 @@ internal class ReportRunner : IReportRunner { } } } - -/** - * Represents a position on a 2D plane - */ -class Position( - val x: Float, - val y: Float -) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt new file mode 100644 index 0000000..262d9ae --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt @@ -0,0 +1,26 @@ +package org.ephyra.acropolis.report.impl.render + +import java.io.InputStream + +class CardBuilder( + private val position2D: Position2D, + + private val size2D: Size2D +) { + private var source: InputStream? = null + private var label: String? = null + + fun withImage(source: InputStream): CardBuilder { + this.source = source + return this + } + + fun withLabel(label: String): CardBuilder { + this.label = label + return this + } + + fun build(renderer: DiagramRenderer) { + + } +} \ No newline at end of file diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt new file mode 100644 index 0000000..a2ed0d7 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt @@ -0,0 +1,9 @@ +package org.ephyra.acropolis.report.impl.render + +/** + * Represents a position on a 2D plane + */ +class Position2D( + val x: Float, + val y: Float +) \ No newline at end of file diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt new file mode 100644 index 0000000..0651977 --- /dev/null +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt @@ -0,0 +1,6 @@ +package org.ephyra.acropolis.report.impl.render + +class Size2D( + val width: Float, + val height: Float +) \ No newline at end of file From 8453b26f8455ef567bb6c9e61cb120573922c5f0 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Mon, 12 Nov 2018 23:47:49 +0000 Subject: [PATCH 18/21] #19 draw images and text from the card builder --- .../acropolis/report/impl/ReportRunner.kt | 3 -- .../report/impl/render/CardBuilder.kt | 37 +++++++++++++++++ .../report/impl/render/DiagramRenderer.kt | 40 +++++++++++++------ 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index e815361..9dd6fa4 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -76,9 +76,6 @@ internal class ReportRunner : IReportRunner { .withImage(imageSource.get(node.representedByResourceName)) .withLabel(node.label) .build(renderer) - - val imageResource = imageSource.get(node.representedByResourceName) - renderer.addImage(position.x.toInt(), position.y.toInt(), imageResource) } renderer.export(File("test-report.png")) } diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt index 262d9ae..03d96d9 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt @@ -21,6 +21,43 @@ class CardBuilder( } fun build(renderer: DiagramRenderer) { + renderer.drawOutline(position2D, size2D) + val imageSource = source + if (imageSource != null) { + drawImage(renderer, imageSource) + } + + val labelText = label + if (labelText != null) { + drawLabel(renderer, labelText) + } + } + + private fun drawLabel(renderer: DiagramRenderer, labelText: String) { + val labelDimensions = renderer.getStringDimensions(labelText) + + val position = Position2D( + (position2D.x + 0.5 * size2D.width - 0.5 * labelDimensions.width).toFloat(), + (position2D.y + 0.9 * size2D.height - 0.5 * labelDimensions.height).toFloat() + ) + + renderer.drawString(labelText, position) + } + + private fun drawImage(renderer: DiagramRenderer, imageSource: InputStream) { + val imageWidthScale = 0.8 + val imageHeightScale = 0.7 + val imagePosition = Position2D( + (position2D.x + size2D.width * (0.5 * (1 - imageWidthScale))).toFloat(), + (position2D.y + size2D.width * (0.5 * (1 - imageWidthScale))).toFloat() + ) + + val imageSize = Size2D( + (size2D.width * imageWidthScale).toFloat(), + (size2D.height * imageHeightScale).toFloat() + ) + + renderer.addImage(imagePosition, imageSize, imageSource) } } \ No newline at end of file diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt index 55aa1ae..3218f6e 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -5,6 +5,9 @@ import java.awt.Color import java.awt.Font import java.awt.Graphics2D import java.awt.Polygon +import java.awt.Rectangle +import java.awt.Stroke +import java.awt.geom.Rectangle2D import java.awt.image.BufferedImage import java.awt.image.BufferedImage.TYPE_INT_RGB import java.io.File @@ -18,18 +21,22 @@ import javax.imageio.ImageIO */ @Suppress("MagicNumber") class DiagramRenderer( - private val width: Int, + width: Int, - private val height: Int + height: Int ) : AutoCloseable { private val targetImg: BufferedImage = BufferedImage(width, height, TYPE_INT_RGB) private val target: Graphics2D + private var font: Font init { target = targetImg.createGraphics() target.color = Color.WHITE target.fillRect(0, 0, width, height) + + font = Font.createFont(Font.TRUETYPE_FONT, File("user/staging/playfair-display/PlayfairDisplay-Regular.ttf")) + font = font.deriveFont(target.font.size * 1.2f) } /** @@ -39,9 +46,9 @@ class DiagramRenderer( * @param positionY The offset of the top side of the image from the top side of the diagram * @param source The input stream to read the image from */ - fun addImage(positionX: Int, positionY: Int, source: InputStream) { + fun addImage(position: Position2D, size: Size2D, source: InputStream) { val img = ImageIO.read(source) - target.drawImage(img, positionX, positionY, 300, 350, null) + target.drawImage(img, position.x.toInt(), position.y.toInt(), size.width.toInt(), size.height.toInt(), null) } /** @@ -77,16 +84,25 @@ class DiagramRenderer( * @param str The text to draw * @param fontFile The file from which to load a font for use in the rendering */ - fun drawString(str: String, fontFile: File) { - if (fontFile.extension != "ttf") { - throw IllegalStateException("Cannot use a font which is not TTF") - } - + fun drawString(str: String, position: Position2D) { target.color = Color.DARK_GRAY - var font = Font.createFont(Font.TRUETYPE_FONT, fontFile) - font = font.deriveFont(target.font.size * 2f) target.font = font - target.drawString(str, 100, 100) + target.drawString(str, position.x, position.y) + } + + fun getStringDimensions(str: String): Size2D { + val fontMetrics = target.getFontMetrics(font) + + val bounds = fontMetrics.getStringBounds(str, target) + + return Size2D(bounds.width.toFloat(), bounds.height.toFloat()) + } + + fun drawOutline(position: Position2D, size: Size2D) { + target.background = Color.YELLOW + target.stroke = BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND) + + target.drawRect(position.x.toInt(), position.y.toInt(), size.width.toInt(), size.height.toInt()) } override fun close() { From 02632c752fef5be233ef69a94de577ff9bbd3ede Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 13 Nov 2018 23:43:12 +0000 Subject: [PATCH 19/21] #19 Add missing doc comments for classes in the render package --- .../org/ephyra/acropolis/report/impl/render/CardBuilder.kt | 3 +++ .../kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt index 03d96d9..536774c 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt @@ -2,6 +2,9 @@ package org.ephyra.acropolis.report.impl.render import java.io.InputStream +/** + * Builder to encapsulate the logic of laying out an image and associated text. + */ class CardBuilder( private val position2D: Position2D, diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt index 0651977..83b8ea5 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt @@ -1,5 +1,8 @@ package org.ephyra.acropolis.report.impl.render +/** + * A size in 2D space + */ class Size2D( val width: Float, val height: Float From 9b1fa61c333d0beea49de6beb9e319f85f326b70 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 13 Nov 2018 23:53:39 +0000 Subject: [PATCH 20/21] #19 Improve layout for columns in rendering --- .../org/ephyra/acropolis/report/impl/ReportRunner.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 9dd6fa4..7755afb 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -53,10 +53,18 @@ internal class ReportRunner : IReportRunner { depthMap.forEach { node, depth -> val currentDepthCount = tempDepthCounts[depth] ?: throw IllegalStateException("missing temp depth count") + val depthCount = depthCounts[depth] ?: throw IllegalStateException("missing depth count") + val x = diagramPadding + depth * cardSeparationHorizontal + depth * tileWidth - val y = diagramPadding + (currentDepthCount - 1) * tileHeight - + (currentDepthCount - 1) * cardSeparationVertical + // This isn't fantastic. Does exact layout if the column is going to be filled and distributes otherwise. + val y: Double = if (depthCount < maxDepthCount) { + diagramPadding + ((diagramHeight - 2 * diagramPadding) / (depthCount + 1)) * currentDepthCount - 0.5 * tileHeight + } + else { + (diagramPadding + (currentDepthCount - 1) * tileHeight + + (currentDepthCount - 1) * cardSeparationVertical).toDouble() + } val position = Position2D( x.toFloat(), From 3406096cef1e02fdcbc5ce932d5e181514ee763f Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Wed, 14 Nov 2018 20:06:49 +0000 Subject: [PATCH 21/21] #19 Fixing detect issues --- .../acropolis/report/impl/ReportRunner.kt | 3 ++- .../report/impl/render/CardBuilder.kt | 20 +++++++++++++++- .../report/impl/render/DiagramRenderer.kt | 23 +++++++++++++++---- .../report/impl/render/Position2D.kt | 2 +- .../acropolis/report/impl/render/Size2D.kt | 2 +- .../acropolis/shell/BootstrapCommand.kt | 9 +++++++- 6 files changed, 50 insertions(+), 9 deletions(-) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt index 7755afb..738ec14 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/ReportRunner.kt @@ -59,7 +59,8 @@ internal class ReportRunner : IReportRunner { // This isn't fantastic. Does exact layout if the column is going to be filled and distributes otherwise. val y: Double = if (depthCount < maxDepthCount) { - diagramPadding + ((diagramHeight - 2 * diagramPadding) / (depthCount + 1)) * currentDepthCount - 0.5 * tileHeight + diagramPadding + ((diagramHeight - 2 * diagramPadding) / (depthCount + 1)) * currentDepthCount + - 0.5 * tileHeight } else { (diagramPadding + (currentDepthCount - 1) * tileHeight diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt index 536774c..b4fffe1 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/CardBuilder.kt @@ -5,6 +5,7 @@ import java.io.InputStream /** * Builder to encapsulate the logic of laying out an image and associated text. */ +@Suppress("MagicNumber") class CardBuilder( private val position2D: Position2D, @@ -13,16 +14,33 @@ class CardBuilder( private var source: InputStream? = null private var label: String? = null + /** + * Configures the image to use for the card being built. + * + * @param source The input stream which will provide the image data + * @return The CardBuilder instance so that method calls can be chained + */ fun withImage(source: InputStream): CardBuilder { this.source = source return this } + /** + * Configures the label to use for the card being built. + * + * @param label The label text + * @return The CardBuilder instance so that method calls can be chained + */ fun withLabel(label: String): CardBuilder { this.label = label return this } + /** + * Creates the card layout and renders it using the provided renderer. + * + * @param renderer The diagram renderer to use for drawing the card + */ fun build(renderer: DiagramRenderer) { renderer.drawOutline(position2D, size2D) @@ -63,4 +81,4 @@ class CardBuilder( renderer.addImage(imagePosition, imageSize, imageSource) } -} \ No newline at end of file +} diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt index 3218f6e..c84a44a 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/DiagramRenderer.kt @@ -40,10 +40,12 @@ class DiagramRenderer( } /** - * Add an image to the diagram at the specified coordinates + * Add an image to the diagram at the specified coordinates. * - * @param positionX The offset of the left side of the image from the left side of the diagram - * @param positionY The offset of the top side of the image from the top side of the diagram + * Note that the input size will cause the image to be scaled to that size. + * + * @param position The position of the top left corner of the image from the top left of the draw space. + * @param size The size that the image should be rendered at * @param source The input stream to read the image from */ fun addImage(position: Position2D, size: Size2D, source: InputStream) { @@ -82,7 +84,7 @@ class DiagramRenderer( * Draw a string of text onto the diagram using the given font. * * @param str The text to draw - * @param fontFile The file from which to load a font for use in the rendering + * @param position The position of the top left corner of the string from the top left of the draw space. */ fun drawString(str: String, position: Position2D) { target.color = Color.DARK_GRAY @@ -90,6 +92,13 @@ class DiagramRenderer( target.drawString(str, position.x, position.y) } + /** + * Gets the dimensions that the input string will have when drawn, given the current font and + * scaling etc. + * + * @param str The string to get dimensions for + * @return The dimensions of the input string when rendered + */ fun getStringDimensions(str: String): Size2D { val fontMetrics = target.getFontMetrics(font) @@ -98,6 +107,12 @@ class DiagramRenderer( return Size2D(bounds.width.toFloat(), bounds.height.toFloat()) } + /** + * Draws an outline, which is a rectangle where only the outline is drawn. + * + * @param position The position to draw the rectangle outline at + * @param size The size of the rectangle to draw + */ fun drawOutline(position: Position2D, size: Size2D) { target.background = Color.YELLOW target.stroke = BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt index a2ed0d7..5900abc 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Position2D.kt @@ -6,4 +6,4 @@ package org.ephyra.acropolis.report.impl.render class Position2D( val x: Float, val y: Float -) \ No newline at end of file +) diff --git a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt index 83b8ea5..cad0223 100644 --- a/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt +++ b/acropolis-report/src/main/kotlin/org/ephyra/acropolis/report/impl/render/Size2D.kt @@ -6,4 +6,4 @@ package org.ephyra.acropolis.report.impl.render class Size2D( val width: Float, val height: Float -) \ No newline at end of file +) diff --git a/acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt b/acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt index 535b08a..f73fd6e 100644 --- a/acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt +++ b/acropolis-shell/src/main/kotlin/org/ephyra/acropolis/shell/BootstrapCommand.kt @@ -7,11 +7,18 @@ import org.springframework.shell.standard.ShellComponent import org.springframework.shell.standard.ShellMethod import java.io.File +/** + * Bootstraps the acropolis system. + * Should be run once when the program is set up to seed the database etc. + */ @ShellComponent class BootstrapCommand { @Autowired private lateinit var graphicalAssetService: IGraphicalAssetService + /** + * Implementation of the bootstrap command + */ @ShellMethod("Bootstrap Acropolis") fun bootstrap() { println("Bootstrapping the acropolis system.") @@ -60,4 +67,4 @@ class BootstrapCommand { GraphicalAssetType.PNG ) } -} \ No newline at end of file +}