From 3964f74da3941fd6363c382a58a6b9c32146e43c Mon Sep 17 00:00:00 2001 From: Yowgf Date: Thu, 10 Dec 2020 15:15:01 -0300 Subject: [PATCH 01/11] Code styling Specially usage of lower camelCase, for some functions, and then also moving stuff in main to a proper function in the class MatrixPrinter. --- src/main/kotlin/tasks/AllTools.kt | 11 ++- src/main/kotlin/tasks/MatrixPrinter.kt | 110 ++++++++++++++++--------- 2 files changed, 75 insertions(+), 46 deletions(-) diff --git a/src/main/kotlin/tasks/AllTools.kt b/src/main/kotlin/tasks/AllTools.kt index 115e2bc..a38e352 100644 --- a/src/main/kotlin/tasks/AllTools.kt +++ b/src/main/kotlin/tasks/AllTools.kt @@ -5,8 +5,8 @@ import utils.* import java.io.File -fun main(args: Array){ - if (args.size < 1){ +fun main(args: Array) { + if (args.size < 1) { return usage(); } val filepath = args[0] @@ -23,9 +23,8 @@ fun main(args: Array){ // generate matrix val matrixOutputFile = changeExtension(filepath, "html") val matrix = MatrixPrinter(actorsDataMap.elements(), resourcesDataMap.elements()) - matrix.populate_matrix(irNode.ir) - matrix.generate_html_file(matrixOutputFile) - + matrix.populateMatrix(irNode.ir) + matrix.generateHtmlFile(matrixOutputFile) // generate .dot files val actionsDot = relativePath(filepath, "actions.dot") @@ -53,4 +52,4 @@ fun main(args: Array){ // print datamap println(datamap.toString().replace('=', ':')) -} \ No newline at end of file +} diff --git a/src/main/kotlin/tasks/MatrixPrinter.kt b/src/main/kotlin/tasks/MatrixPrinter.kt index b7d5da2..09473cc 100644 --- a/src/main/kotlin/tasks/MatrixPrinter.kt +++ b/src/main/kotlin/tasks/MatrixPrinter.kt @@ -8,6 +8,7 @@ import java.io.InputStream import java.io.OutputStreamWriter import java.io.FileOutputStream import java.io.File +import java.io.FileWriter import kotlinx.html.* import kotlinx.html.dom.* @@ -18,54 +19,58 @@ import javax.xml.parsers.DocumentBuilderFactory import javax.xml.transform.stream.StreamResult import javax.xml.transform.dom.DOMSource +import com.google.gson.Gson +import com.google.gson.GsonBuilder + class MatrixPrinter { private val resources: Map - private val indexed_resources: Array + private val indexedResources: Array private val actors: Map - private val indexed_actors: Array + private val indexedActors: Array private val matrix: Array>> - constructor(actors: Set, resources: Set){ - + constructor(actors: Set, resources: Set) { + // associate the resources names with the matrix indexes var index: Int = 0 this.resources = resources.associateWith({index++}); - indexed_resources = Array(resources.size){""} - for((key, value) in this.resources){ - indexed_resources[value] = key + indexedResources = Array(resources.size) {""} + for ((key, value) in this.resources) { + indexedResources[value] = key } - + // associate the actors names with the matrix indexes index = 0 this.actors = actors.associateWith({index++}); - indexed_actors = Array(actors.size){""} - for((key, value) in this.actors){ - indexed_actors[value] = key + indexedActors = Array(actors.size) {""} + for ((key, value) in this.actors) { + indexedActors[value] = key } - + // create matrix - this.matrix = Array>>(actors.size){ - Array>(resources.size){ + this.matrix = Array>>(actors.size) { + Array>(resources.size) { mutableMapOf("Reads" to 0, "Updates" to 0, "Deletes" to 0) } } } - public fun populate_matrix(ir: IR){ + public fun populateMatrix(ir: IR) { //transform the IR data in a matrix - for((actor, actions) in (ir as NonTerminal).nonTerminal ){ - for ((action, _resources) in (actions as NonTerminal).nonTerminal){ - (_resources as Terminal).terminal.forEach{resource -> + for ((actor, actions) in (ir as NonTerminal).nonTerminal) { + for ((action, _resources) in (actions as NonTerminal).nonTerminal) { + (_resources as Terminal).terminal.forEach { + resource -> (this.matrix[this.actors[actor] as Int][this.resources[resource] as Int] as MutableMap).put(action, 1) } } } } - public fun generate_html_file(htmFileName: String){ + public fun generateHtmlFile(htmFileName: String) { val document = DocumentBuilderFactory.newInstance(). newDocumentBuilder().newDocument() - + //kotlinx.html notation to generate a html page val html = document.create.html { head { @@ -80,7 +85,7 @@ class MatrixPrinter { } th, td { padding: 8px 4px; - text-align: left; + text-align: left; } p { margin: 4px 0; @@ -91,22 +96,22 @@ class MatrixPrinter { } } body { - table{ - tr{ - th{+" "} - for (resource_name in indexed_resources){ - th{+resource_name} + table { + tr { + th {+" "} + for (resource_name in indexedResources) { + th {+resource_name} } } - for (i in 0..(matrix.size)-1){ + for (i in 0..(matrix.size)-1) { tr { - th {+indexed_actors[i]} - for (j in 0..(matrix[i].size)-1){ + th {+indexedActors[i]} + for (j in 0..(matrix[i].size)-1) { val cell = matrix[i][j] td { - p{+"Reads: ${cell["Reads"]}"} - p{+"Updates: ${cell["Updates"]}"} - p{+"Deletes: ${cell["Deletes"]}"} + p {+"Reads: ${cell["Reads"]}"} + p {+"Updates: ${cell["Updates"]}"} + p {+"Deletes: ${cell["Deletes"]}"} } } } @@ -115,7 +120,7 @@ class MatrixPrinter { } } - with(TransformerFactory.newInstance().newTransformer()){ + with(TransformerFactory.newInstance().newTransformer()) { setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no") setOutputProperty(OutputKeys.METHOD, "xml") setOutputProperty(OutputKeys.INDENT, "yes") @@ -125,10 +130,31 @@ class MatrixPrinter { StreamResult(OutputStreamWriter(FileOutputStream(htmFileName), "UTF-8"))) } } + + public fun generateJSONFile(JSONFIleName: String) { + // Keys are actor, resource, action + val gsonMatrix: Map>> = + { + for (actor in indexedActors) { + for (resource in indexedResources) { + + } + } + mapOf() + } + + + val gsonPretty = GsonBuilder().setPrettyPrinting().create() + val jsonTutsArrayPretty: String = gsonPretty.toJson(matrix) + + val jsonOutFile = FileWriter(JSONFIleName) + jsonOutFile.write(jsonTutsArrayPretty) + jsonOutFile.close() + } } -fun main(args: Array){ - if (args.size < 1){ +fun main(args: Array) { + if (args.size < 1) { return usage(); } @@ -142,10 +168,14 @@ fun main(args: Array){ val actorsDataMap = datamap.getValue("Actors") val resourcesDataMap = datamap.getValue("Resources") - // generate matrix - val matrixOutputFile = changeExtension(filepath, "html") + // generate matrix val matrix = MatrixPrinter(actorsDataMap.elements(), resourcesDataMap.elements()) - matrix.populate_matrix(irNode.ir) - matrix.generate_html_file(matrixOutputFile) + matrix.populateMatrix(irNode.ir) -} \ No newline at end of file + // Generate output files + var matrixOutputFile = changeExtension(filepath, "html") + matrix.generateHtmlFile(matrixOutputFile) + + matrixOutputFile = changeExtension(filepath, "json"); + matrix.generateJSONFile(matrixOutputFile); +} From eb23e78dd404b92f60760f29bad9453b5682af05 Mon Sep 17 00:00:00 2001 From: Yowgf Date: Wed, 16 Dec 2020 23:36:04 -0300 Subject: [PATCH 02/11] Refactoring and doc Some unused imports were removed, some things renamed, and so on. --- src/main/kotlin/tasks/MatrixPrinter.kt | 100 +++++++++++++++++++------ 1 file changed, 78 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/tasks/MatrixPrinter.kt b/src/main/kotlin/tasks/MatrixPrinter.kt index 09473cc..fd5abbf 100644 --- a/src/main/kotlin/tasks/MatrixPrinter.kt +++ b/src/main/kotlin/tasks/MatrixPrinter.kt @@ -1,10 +1,8 @@ -package tasks; +package tasks import hapi.* import utils.* -import java.io.FileInputStream -import java.io.InputStream import java.io.OutputStreamWriter import java.io.FileOutputStream import java.io.File @@ -19,9 +17,24 @@ import javax.xml.parsers.DocumentBuilderFactory import javax.xml.transform.stream.StreamResult import javax.xml.transform.dom.DOMSource -import com.google.gson.Gson import com.google.gson.GsonBuilder +/** + * The class responsible for the matrix representation of a Hapi policy. + *

+ * It implements the Kotlin matrix representation, as well as routines to + * generate its respective serialized formats, namely HTML and JSON. + * Usage example: + *

+ *     // generate matrix
+ *     val matrix = MatrixPrinter(actorsDataMap.elements(),
+ *                                resourcesDataMap.elements())
+ *     matrix.populateMatrix(irNode.ir)
+ *     // HTML and JSON
+ *     matrix.generateHtmlFile("Output.html")
+ *     matrix.generateJsonFile("Output.json")
+ * 
+ */ class MatrixPrinter { private val resources: Map private val indexedResources: Array @@ -29,11 +42,18 @@ class MatrixPrinter { private val indexedActors: Array private val matrix: Array>> + /** + * Primary constructor. + * Constructs the internal objects indexedResources and indexedActors, and + * initializes matrix as a dummy object. + * @param actors names of the actors + * @param resources names of the resources + */ constructor(actors: Set, resources: Set) { // associate the resources names with the matrix indexes var index: Int = 0 - this.resources = resources.associateWith({index++}); + this.resources = resources.associateWith {index++} indexedResources = Array(resources.size) {""} for ((key, value) in this.resources) { indexedResources[value] = key @@ -41,7 +61,7 @@ class MatrixPrinter { // associate the actors names with the matrix indexes index = 0 - this.actors = actors.associateWith({index++}); + this.actors = actors.associateWith {index++} indexedActors = Array(actors.size) {""} for ((key, value) in this.actors) { indexedActors[value] = key @@ -55,6 +75,12 @@ class MatrixPrinter { } } + /** + * Fills the matrix with the ir actors, resources and their corresponding + * action status, for each action available. + * @param ir the policy intermediate representation + * @see IR + */ public fun populateMatrix(ir: IR) { //transform the IR data in a matrix for ((actor, actions) in (ir as NonTerminal).nonTerminal) { @@ -67,6 +93,15 @@ class MatrixPrinter { } } + /** + * Generates and fills the target HTML serialized file with the properly + * formatted contents of the Hapi matrix. + *

+ * Makes use of the Kotlin DSL for HTML + * kotlinx.html + * to easily create the java object. + * @param htmFileName target file + */ public fun generateHtmlFile(htmFileName: String) { val document = DocumentBuilderFactory.newInstance(). newDocumentBuilder().newDocument() @@ -131,31 +166,52 @@ class MatrixPrinter { } } - public fun generateJSONFile(JSONFIleName: String) { - // Keys are actor, resource, action - val gsonMatrix: Map>> = - { - for (actor in indexedActors) { - for (resource in indexedResources) { - - } - } - mapOf() + /** + * Generates and fills the target JSON serialized file with the properly + * formatted contents of the Hapi matrix. + *

+ * Makes use of the JSON serialization and deserialization library + * Gson + * to easily create the java object. + * @param jsonFileName the target file + */ + public fun generateJsonFile(jsonFileName: String) { + /* + Aims to generate a three-layer deep map, so that GsonBuilder may be able + to build a JSON with the right names associated. + At a conceptual level, keys are actor, resource, action, respectively. + */ + val gsonMap: Map>> = + mutableMapOf>>().apply { + putAll(indexedActors.toSet().associateWith { actor -> + mutableMapOf>().apply { + putAll(indexedResources.toSet().associateWith { resource -> + matrix[actors[actor] as Int][resources[resource] as Int] + }) + } + }) } - val gsonPretty = GsonBuilder().setPrettyPrinting().create() - val jsonTutsArrayPretty: String = gsonPretty.toJson(matrix) + val jsonTutsArrayPretty: String = gsonPretty.toJson(gsonMap) - val jsonOutFile = FileWriter(JSONFIleName) + val jsonOutFile = FileWriter(jsonFileName) jsonOutFile.write(jsonTutsArrayPretty) jsonOutFile.close() } } +/** + * Builds the matrix and generates both HTML and JSON output files. + * This is called by the gradle task "matrix". + * + * @param args the Hapi policy file name. The output serialized files shall have + * the same root name (everything but the extension), including the + * specified directory. + */ fun main(args: Array) { if (args.size < 1) { - return usage(); + return usage() } val filepath = args[0] @@ -176,6 +232,6 @@ fun main(args: Array) { var matrixOutputFile = changeExtension(filepath, "html") matrix.generateHtmlFile(matrixOutputFile) - matrixOutputFile = changeExtension(filepath, "json"); - matrix.generateJSONFile(matrixOutputFile); + matrixOutputFile = changeExtension(filepath, "json") + matrix.generateJsonFile(matrixOutputFile); } From 01365bbfbcc8f35ae41cb9f3f7f04190b1416f11 Mon Sep 17 00:00:00 2001 From: Yowgf Date: Wed, 16 Dec 2020 23:37:10 -0300 Subject: [PATCH 03/11] Documentation --- src/main/kotlin/tasks/AllTools.kt | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/tasks/AllTools.kt b/src/main/kotlin/tasks/AllTools.kt index a38e352..fea1be5 100644 --- a/src/main/kotlin/tasks/AllTools.kt +++ b/src/main/kotlin/tasks/AllTools.kt @@ -5,6 +5,15 @@ import utils.* import java.io.File +/** + * In a single function block, runs all serialization tools currently supported. + * This is called by the gradle task "all-tools" and "build-all-tools", and as + * of now, is used mainly by Hapi Visualizer as a facilitator. + * + * @param args the Hapi policy file name. The output serialized files shall have + * the same root name (everything but the extension), including the + * specified directory. + */ fun main(args: Array) { if (args.size < 1) { return usage(); @@ -20,13 +29,17 @@ fun main(args: Array) { val actorsDataMap = datamap.getValue("Actors") val resourcesDataMap = datamap.getValue("Resources") - // generate matrix - val matrixOutputFile = changeExtension(filepath, "html") + // matrix creation val matrix = MatrixPrinter(actorsDataMap.elements(), resourcesDataMap.elements()) matrix.populateMatrix(irNode.ir) + + // generates HTML and JSON + var matrixOutputFile = changeExtension(filepath, "html") matrix.generateHtmlFile(matrixOutputFile) + matrixOutputFile = changeExtension(filepath, "json") + matrix.generateJsonFile(matrixOutputFile) - // generate .dot files + // generates .dot files val actionsDot = relativePath(filepath, "actions.dot") var file = File(actionsDot); file.bufferedWriter().use { out -> @@ -45,7 +58,7 @@ fun main(args: Array) { out.write(resourcesDataMap.dot_graph()); } - // generate Yaml + // generates YAML val yamlOutputFile = changeExtension(filepath, "yaml") val yamlGenerator = YAMLGenerator(); yamlGenerator.generate(irNode.ir, datamap, yamlOutputFile); From c936a8824bcfa338046f81fbdcda7678e9c8e9d7 Mon Sep 17 00:00:00 2001 From: Yowgf Date: Wed, 16 Dec 2020 23:38:26 -0300 Subject: [PATCH 04/11] Ignore IntelliJ IDEA config folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 778892e..eb495ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea .vscode /build From af841aabf8ca2ae44455ce5ad86dcc2c5709e76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vinicius=20Juli=C3=A3o=20R?= <40807325+vrjuliao@users.noreply.github.com> Date: Fri, 29 Jan 2021 14:29:16 -0300 Subject: [PATCH 05/11] Error messages (#8) * init issue of error messages manipulation * error(messages): showing runtime error messages with the file coordinates * error(messages): DONE, but lacking unit tests * fix(error messages): DONE * fix(error messages): removing log files * fix(test): Unit tests description * fix(test): Unit tests function names --- src/main/kotlin/hapi/DataVisitor.kt | 7 ++- src/main/kotlin/hapi/Eval.kt | 16 +---- src/main/kotlin/hapi/IRVisitor.kt | 63 ++++++++++++++----- .../kotlin/hapi/error/HapiErrorListener.kt | 19 ++++++ .../kotlin/hapi/error/HapiRuntimeException.kt | 22 +++++++ src/main/kotlin/utils/Utils.kt | 1 - src/test/kotlin/integration/EvaluationTest.kt | 27 +++++++- src/test/kotlin/unit/IRVisitorTest.kt | 8 +-- src/test/kotlin/unit/ParsingTest.kt | 42 ++++++++++++- 9 files changed, 166 insertions(+), 39 deletions(-) create mode 100644 src/main/kotlin/hapi/error/HapiErrorListener.kt create mode 100644 src/main/kotlin/hapi/error/HapiRuntimeException.kt diff --git a/src/main/kotlin/hapi/DataVisitor.kt b/src/main/kotlin/hapi/DataVisitor.kt index 437b36b..d9f2204 100644 --- a/src/main/kotlin/hapi/DataVisitor.kt +++ b/src/main/kotlin/hapi/DataVisitor.kt @@ -1,8 +1,10 @@ package hapi import java.io.File +import java.io.FileNotFoundException import utils.* +import hapi.error.* import HapiParser import HapiBaseVisitor @@ -25,8 +27,11 @@ class DataVisitor(val root: String) : HapiBaseVisitor() { override fun visitImportStmt(ctx: HapiParser.ImportStmtContext): DataMap { val module = this.root + "/" + ctx.ID().toString() + ".hp" - return File(module).let { + if (!it.exists()){ + val message = "Module '${ctx.ID()}' does not exist" + throw HapiRuntimeException(ctx.ID(), message) + } evalDataMap(it.readText(), this.root) } } diff --git a/src/main/kotlin/hapi/Eval.kt b/src/main/kotlin/hapi/Eval.kt index faeb81c..bcaa914 100644 --- a/src/main/kotlin/hapi/Eval.kt +++ b/src/main/kotlin/hapi/Eval.kt @@ -1,5 +1,6 @@ package hapi +import hapi.error.HapiErrorListener import org.antlr.v4.runtime.* import org.antlr.v4.runtime.tree.ParseTree import org.antlr.v4.runtime.misc.ParseCancellationException @@ -9,22 +10,11 @@ import java.io.InputStream import HapiLexer import HapiParser -val errorListener = object : BaseErrorListener() { - override fun syntaxError( - recognizer: Recognizer<*, *>?, - offendingSymbol: Any?, - line: Int, - charPositionInLine: Int, - message: String, - e: RecognitionException? - ) = throw ParseCancellationException("line " + line + ":" + charPositionInLine + " " + message) -} - fun tokenize(source: String): CommonTokenStream = CharStreams.fromString(source).let { val lexer = HapiLexer(it).apply { removeErrorListeners() - addErrorListener(errorListener) + addErrorListener(HapiErrorListener()) } CommonTokenStream(lexer) } @@ -32,7 +22,7 @@ fun tokenize(source: String): CommonTokenStream = fun parse(tokens: CommonTokenStream): HapiParser.ProgramContext = HapiParser(tokens).apply { removeErrorListeners() - addErrorListener(errorListener) + addErrorListener(HapiErrorListener()) }.program() fun evalDataMap(source: String, root: String): DataMap = diff --git a/src/main/kotlin/hapi/IRVisitor.kt b/src/main/kotlin/hapi/IRVisitor.kt index 777255c..807d442 100644 --- a/src/main/kotlin/hapi/IRVisitor.kt +++ b/src/main/kotlin/hapi/IRVisitor.kt @@ -3,6 +3,7 @@ package hapi import java.io.File import utils.* +import hapi.error.* import HapiBaseVisitor import HapiParser @@ -31,7 +32,11 @@ class IRVisitor( if (ctx.value().isEmpty()) // attribute has no value -> top of the lattice datamap[attr]!!.atoms(datamap[attr]!!.TOP).unwrap() else - ctx.value().flatMap{ datamap[attr]!!.atoms(it.ID().toString()).unwrap()}.toSet() + try { + ctx.value().flatMap{datamap[attr]!!.atoms(it.ID().toString()).unwrap()}.toSet() + } catch (e:Exception){ + throw HapiRuntimeException(ctx.ID(), (e.message!!)) + } else // clausule has no such attribute -> empty set setOf(datamap[attr]!!.BOTTOM) }) @@ -48,7 +53,7 @@ class IRVisitor( if (main != null) return IRNode(main) else - throw Exception("no entry point 'main' provided") + throw HapiRuntimeException("no entry point 'main' provided") } override fun visitLibrary(ctx: HapiParser.LibraryContext ): ASTNode { @@ -71,7 +76,8 @@ class IRVisitor( when (ast) { is EnvNode -> ast - else -> throw Exception("can't import an executable file") + else -> throw HapiRuntimeException(ctx.ID(), + "can't import an executable file") } } } @@ -94,8 +100,10 @@ class IRVisitor( override fun visitAttributeExpr(ctx: HapiParser.AttributeExprContext): ASTNode { ctx.attribute().forEach { - if (!this.datamap.containsKey(it.ID().toString())) - throw Exception("undefined attribute ${it.ID()}") + if (!this.datamap.containsKey(it.ID().toString())){ + val message = "Undefined attribute \"${it.ID()}\"" + throw HapiRuntimeException(it.ID(), message) + } } val type = inferTypeFrom(ctx.getParent().getRuleIndex()) @@ -113,7 +121,7 @@ class IRVisitor( if (ir != null) return IRNode(ir) else - throw Exception("undefined name: ${name}") + throw HapiRuntimeException(ctx.ID().component1(), "undefined name: ${name}") } override fun visitDenyExceptExpr(ctx: HapiParser.DenyExceptExprContext): ASTNode { @@ -121,19 +129,31 @@ class IRVisitor( val denyAttrIR = (denyAttr as IRNode).ir val ir = ctx.allowExpr() - .map{(visit(it) as IRNode).ir} - .fold(denyAttrIR, { acc, ir -> acc.minus(ir).unwrap() }) + .map{ + val result = (visit(it) as IRNode).ir + if(result.type != IRType.ALLOW) + throw HapiRuntimeException(it.getStart(), + "${it.getStart().getText()} is a DENY expression, expected ALLOW") + else + result + }.fold(denyAttrIR, { acc, ir -> acc.minus(ir).unwrap() }) return IRNode(ir) } - + override fun visitDenyAllExceptExpr(ctx: HapiParser.DenyAllExceptExprContext): ASTNode { val top = this.datamap.mapValues { setOf() } val topIR = IR.from(top, IRType.ALLOW, this.datamap.keys.toList()) val ir = ctx.allowExpr() - .map{(visit(it) as IRNode).ir} - .fold(topIR, { acc, ir -> acc.plus(ir).unwrap() }) + .map{ + val result = (visit(it) as IRNode).ir + if(result.type != IRType.ALLOW) + throw HapiRuntimeException(it.getStart(), + "${it.getStart().getText()} is a DENY expression, expected ALLOW") + else + result + }.fold(topIR, { acc, ir -> acc.plus(ir).unwrap()}) return IRNode(ir) } @@ -143,8 +163,14 @@ class IRVisitor( val allowAttrIR = (allowAttr as IRNode).ir val ir = ctx.denyExpr() - .map{(visit(it) as IRNode).ir} - .fold(allowAttrIR, { acc, ir -> acc.minus(ir).unwrap() }) + .map{ + val result = (visit(it) as IRNode).ir + if(result.type != IRType.DENY) + throw HapiRuntimeException(it.getStart(), + "${it.getStart().getText()} is an ALLOW expression, expected DENY") + else + result + }.fold(allowAttrIR, { acc, ir -> acc.minus(ir).unwrap()}) return IRNode(ir) } @@ -154,9 +180,14 @@ class IRVisitor( val topIR = IR.from(top, IRType.ALLOW, this.datamap.keys.toList()) val ir = ctx.denyExpr() - .map{(visit(it) as IRNode).ir} - .fold(topIR, { acc, ir -> acc.minus(ir).unwrap() }) - + .map{ + val result = (visit(it) as IRNode).ir + if(result.type != IRType.DENY) + throw HapiRuntimeException(it.getStart(), + "${it.getStart().getText()} is an ALLOW expression, expected DENY") + else + result + }.fold(topIR, { acc, ir -> acc.minus(ir).unwrap() }) return IRNode(ir) } } \ No newline at end of file diff --git a/src/main/kotlin/hapi/error/HapiErrorListener.kt b/src/main/kotlin/hapi/error/HapiErrorListener.kt new file mode 100644 index 0000000..2e1cdec --- /dev/null +++ b/src/main/kotlin/hapi/error/HapiErrorListener.kt @@ -0,0 +1,19 @@ +package hapi.error + +import org.antlr.v4.runtime.* +import org.antlr.v4.runtime.tree.ParseTree +import org.antlr.v4.runtime.misc.ParseCancellationException + +/* +create a decision map to manipulate errors that occurs on each Token in Hapi.g4 + */ + +class HapiErrorListener(): BaseErrorListener() { + override fun syntaxError( + recognizer: Recognizer<*, *>?, offendingSymbol: Any?, line: Int, + charPositionInLine: Int, message: String, e: RecognitionException?){ + val errorMessage = "line " + line + ":" + charPositionInLine + " " + message + System.out.println(errorMessage) + throw ParseCancellationException(errorMessage) + } +} \ No newline at end of file diff --git a/src/main/kotlin/hapi/error/HapiRuntimeException.kt b/src/main/kotlin/hapi/error/HapiRuntimeException.kt new file mode 100644 index 0000000..c5d2572 --- /dev/null +++ b/src/main/kotlin/hapi/error/HapiRuntimeException.kt @@ -0,0 +1,22 @@ +package hapi.error + +import java.lang.RuntimeException +import org.antlr.v4.runtime.tree.TerminalNode +import org.antlr.v4.runtime.Token + +class HapiRuntimeException(override val message: String): RuntimeException(message){ + + companion object { + operator fun invoke(token:TerminalNode , message: String): HapiRuntimeException { + return HapiRuntimeException(token.getSymbol(), message) + } + + operator fun invoke(token:Token , message: String): HapiRuntimeException { + val charPosition = token.getCharPositionInLine() + val line = token.getLine() + val msg = "line " + line + ":" + charPosition + " " + message + System.out.println(msg) + return HapiRuntimeException(msg) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/utils/Utils.kt b/src/main/kotlin/utils/Utils.kt index e42aaa8..213d66e 100644 --- a/src/main/kotlin/utils/Utils.kt +++ b/src/main/kotlin/utils/Utils.kt @@ -22,7 +22,6 @@ fun relativePath(p1: String, p2: String): String { return getDirName(p1) + "/" + p2; } - fun filePathInDir(file: String, dir: String): String { return dir + "/" + file; } \ No newline at end of file diff --git a/src/test/kotlin/integration/EvaluationTest.kt b/src/test/kotlin/integration/EvaluationTest.kt index 7f6d73c..b743ece 100644 --- a/src/test/kotlin/integration/EvaluationTest.kt +++ b/src/test/kotlin/integration/EvaluationTest.kt @@ -110,9 +110,30 @@ class EvaluationTest { } val e1 = assertFailsWith{ irFromString(program("K: K2")) } - assertEquals("undefined value K2", e1.message) + assertEquals("line 10:12 undefined value K2", e1.message) val e2 = assertFailsWith{ irFromString(program("L: L1")) } - assertEquals("undefined attribute L", e2.message) + assertEquals("line 10:12 Undefined attribute \"L\"", e2.message) } -} \ No newline at end of file + + @Test + @DisplayName("Non existent module") + fun nonExistentModule() { + val program = + """ + import inexistentModule; + data P = P1; + + main = + DENY + EXCEPT { + ALLOW { + P: P1 + } + }; + """ + + val e1 = assertFailsWith{irFromString(program)} + assertEquals("line 2:13 Module 'inexistentModule' does not exist", e1.message) + } +} diff --git a/src/test/kotlin/unit/IRVisitorTest.kt b/src/test/kotlin/unit/IRVisitorTest.kt index 6ad89ab..0c93d36 100644 --- a/src/test/kotlin/unit/IRVisitorTest.kt +++ b/src/test/kotlin/unit/IRVisitorTest.kt @@ -28,7 +28,7 @@ class IRVisitorTest { val file = "src/test/fixtures/wrong-name/Main.hp" val exception = assertFailsWith { irFromFile(file) } - assertEquals("undefined name: WrongName::bob", exception.message) + assertEquals("line 6:4 undefined name: WrongName::bob", exception.message) } @Test @@ -78,9 +78,9 @@ class IRVisitorTest { """ ) val messages = listOf( - "expected type ALLOW got DENY", - "expected type DENY got ALLOW", - "expected type ALLOW got DENY" + "line 10:10 denyP1 is a DENY expression, expected ALLOW", + "line 10:10 allowP1 is an ALLOW expression, expected DENY", + "line 14:10 denyP1 is a DENY expression, expected ALLOW" ) for (i in 0 until programs.size){ val exception = assertFailsWith{ irFromString(programs.get(i)) } diff --git a/src/test/kotlin/unit/ParsingTest.kt b/src/test/kotlin/unit/ParsingTest.kt index 8d90dc3..f10a040 100644 --- a/src/test/kotlin/unit/ParsingTest.kt +++ b/src/test/kotlin/unit/ParsingTest.kt @@ -39,7 +39,7 @@ class ParsingTest { } @Test - @DisplayName("Should throw ParseCancellationException on syntax rrror") + @DisplayName("Should throw ParseCancellationException on syntax error") fun shouldThrowParseCancellationExceptionOnSyntaxError(){ val program = """ @@ -73,4 +73,44 @@ class ParsingTest { """ assertNotNull(parse(tokenize(program))) } + + @Test + @DisplayName("Invalid import statement - missing comma") + fun invalidSyntaxMissingComma(){ + val program = + """ + import somemodule + + data Prop = P1; + + denyP1 = DENY { + Prop: P1 + }; + main = + ALLOW + EXCEPT { + denyP1 + }; + """ + val error = "line 4:6 missing ';' at 'data'" + val e1 = assertFailsWith{parse(tokenize(program))} + assertEquals(error, e1.message) + } + + @Test + @DisplayName("Invalid EXCEPT - missing curly braces") + fun invalidSyntaxMissingBraces(){ + val program = + """ + data Prop = P1; + main = + ALLOW + EXCEPT + denyP1 + }; + """ + val error = "line 6:10 missing '{' at 'denyP1'" + val e1 = assertFailsWith{parse(tokenize(program))} + assertEquals(error, e1.message) + } } \ No newline at end of file From d02c24c769767087228bd5f6a3786109bff806b3 Mon Sep 17 00:00:00 2001 From: Yowgf <48073242+Yowgf@users.noreply.github.com> Date: Fri, 12 Feb 2021 11:53:13 -0300 Subject: [PATCH 06/11] Fixing first line of printed YAML (#9) --- src/main/kotlin/tasks/YAML.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/tasks/YAML.kt b/src/main/kotlin/tasks/YAML.kt index 33cf968..f1aede3 100644 --- a/src/main/kotlin/tasks/YAML.kt +++ b/src/main/kotlin/tasks/YAML.kt @@ -12,7 +12,7 @@ class YAMLGenerator { file.bufferedWriter().use { out -> val resources = datamap["Resources"]!!; - out.write("data: ${resources.atoms(resources.TOP)}\n"); + out.write("data: ${resources.atoms(resources.TOP).unwrap()}\n"); out.write("rules:\n"); From 7e0fdb23d556930bd1bc4dd21dbda6342352c855 Mon Sep 17 00:00:00 2001 From: Yowgf <48073242+Yowgf@users.noreply.github.com> Date: Thu, 25 Feb 2021 16:20:03 -0300 Subject: [PATCH 07/11] Move to ./hapi folder (#11) These should be separated from the tests of other modules. Soon we plan to add the ./tasks folders, for unit tests that concern the "tasks" --- src/test/kotlin/unit/{ => hapi}/DataVisitorTest.kt | 0 src/test/kotlin/unit/{ => hapi}/IRVisitorTest.kt | 0 src/test/kotlin/unit/{ => hapi}/ParsingTest.kt | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/test/kotlin/unit/{ => hapi}/DataVisitorTest.kt (100%) rename src/test/kotlin/unit/{ => hapi}/IRVisitorTest.kt (100%) rename src/test/kotlin/unit/{ => hapi}/ParsingTest.kt (100%) diff --git a/src/test/kotlin/unit/DataVisitorTest.kt b/src/test/kotlin/unit/hapi/DataVisitorTest.kt similarity index 100% rename from src/test/kotlin/unit/DataVisitorTest.kt rename to src/test/kotlin/unit/hapi/DataVisitorTest.kt diff --git a/src/test/kotlin/unit/IRVisitorTest.kt b/src/test/kotlin/unit/hapi/IRVisitorTest.kt similarity index 100% rename from src/test/kotlin/unit/IRVisitorTest.kt rename to src/test/kotlin/unit/hapi/IRVisitorTest.kt diff --git a/src/test/kotlin/unit/ParsingTest.kt b/src/test/kotlin/unit/hapi/ParsingTest.kt similarity index 100% rename from src/test/kotlin/unit/ParsingTest.kt rename to src/test/kotlin/unit/hapi/ParsingTest.kt From 1a74dcc769ef883445dc43619c58534a464655c3 Mon Sep 17 00:00:00 2001 From: Yowgf <48073242+Yowgf@users.noreply.github.com> Date: Thu, 11 Mar 2021 17:23:29 -0300 Subject: [PATCH 08/11] Check that datamap matches 3D format (#10) * Checks if given datamap has 3 entries And that these entries match, in order, ("Actors", "Actions", "Resources") * Added check3D * Fixed names of classes * Renamed Check3D class * Moved check to inside the class * Added help to YAML testing * Fixtures to facilitate YAML tests * YAMLGenerator tests * Just change a comment * Delete the temp. result form yaml task --- src/main/kotlin/tasks/YAML.kt | 4 ++ src/main/kotlin/utils/DataMapOrderChecker.kt | 20 +++++++ src/test/fixtures/YAML/Expected.yaml | 18 ++++++ src/test/fixtures/YAML/Main.hp | 13 +++++ src/test/fixtures/YAML/WrongNames.hp | 13 +++++ src/test/fixtures/YAML/WrongOrder.hp | 13 +++++ src/test/kotlin/helpers/Helpers.kt | 21 ++++++- src/test/kotlin/unit/tasks/YAMLTest.kt | 58 ++++++++++++++++++++ 8 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/utils/DataMapOrderChecker.kt create mode 100644 src/test/fixtures/YAML/Expected.yaml create mode 100644 src/test/fixtures/YAML/Main.hp create mode 100644 src/test/fixtures/YAML/WrongNames.hp create mode 100644 src/test/fixtures/YAML/WrongOrder.hp create mode 100644 src/test/kotlin/unit/tasks/YAMLTest.kt diff --git a/src/main/kotlin/tasks/YAML.kt b/src/main/kotlin/tasks/YAML.kt index f1aede3..44ecfdb 100644 --- a/src/main/kotlin/tasks/YAML.kt +++ b/src/main/kotlin/tasks/YAML.kt @@ -8,6 +8,8 @@ import utils.* class YAMLGenerator { fun generate(ir: IR, datamap: DataMap, filename: String) { + DataMapOrderChecker(datamap) // Check that datamap has right keys + val file = File(filename); file.bufferedWriter().use { out -> @@ -40,7 +42,9 @@ fun main(args: Array) { File(file).let { val root = getDirName(file) val source = it.readText() + val datamap = evalDataMap(source, root) + val ast = evalIR(source, root, datamap) as IRNode val outputFile = changeExtension(file, "yaml") diff --git a/src/main/kotlin/utils/DataMapOrderChecker.kt b/src/main/kotlin/utils/DataMapOrderChecker.kt new file mode 100644 index 0000000..41c0927 --- /dev/null +++ b/src/main/kotlin/utils/DataMapOrderChecker.kt @@ -0,0 +1,20 @@ +package utils + +import hapi.* + +class DataMapOrderError(message: String) : Exception(message) + +/* Checks that the datamap provided has exactly three keys, in the + * following order: ("Actors", "Actions", "Resources"). + */ +class DataMapOrderChecker(datamap: DataMap) { + init { + val dmKeys = datamap.keys.toList() + val expectedDmKeys = listOf("Actors", "Actions", "Resources") + + if (dmKeys != expectedDmKeys) { + throw DataMapOrderError("Expected data statements for ${expectedDmKeys.toString()}" + + ", got ${dmKeys.toString()}") + } + } +} diff --git a/src/test/fixtures/YAML/Expected.yaml b/src/test/fixtures/YAML/Expected.yaml new file mode 100644 index 0000000..135f678 --- /dev/null +++ b/src/test/fixtures/YAML/Expected.yaml @@ -0,0 +1,18 @@ +data: [res3, res2, res1] +rules: + - identities: + users: Bob + Deletes: + data: [res3, res2, res1] + Updates: + data: [res3, res2, res1] + Reads: + data: [res3, res2, res1] + - identities: + users: Alice + Deletes: + data: [res3, res2, res1] + Updates: + data: [res3, res2, res1] + Reads: + data: [res3, res2, res1] diff --git a/src/test/fixtures/YAML/Main.hp b/src/test/fixtures/YAML/Main.hp new file mode 100644 index 0000000..ba1c47a --- /dev/null +++ b/src/test/fixtures/YAML/Main.hp @@ -0,0 +1,13 @@ +data Actors = Analyst(Alice, Bob); +data Actions = Reads, Updates, Deletes; +data Resources = res1, res2, res3; + +main = + DENY + EXCEPT { + ALLOW { + Actors: Analyst + Actions + Resources + } + }; diff --git a/src/test/fixtures/YAML/WrongNames.hp b/src/test/fixtures/YAML/WrongNames.hp new file mode 100644 index 0000000..09a3aa5 --- /dev/null +++ b/src/test/fixtures/YAML/WrongNames.hp @@ -0,0 +1,13 @@ +data Actors = Analyst(Alice, Bob); +data Actions = Reads, Updates, Deletes; +data Resource = res1, res2, res3; + +main = + DENY + EXCEPT { + ALLOW { + Actors: Analyst + Actions + Resource + } + }; diff --git a/src/test/fixtures/YAML/WrongOrder.hp b/src/test/fixtures/YAML/WrongOrder.hp new file mode 100644 index 0000000..be4816e --- /dev/null +++ b/src/test/fixtures/YAML/WrongOrder.hp @@ -0,0 +1,13 @@ +data Actors = Analyst(Alice, Bob); +data Resources = res1, res2, res3; +data Actions = Reads, Updates, Deletes; + +main = + DENY + EXCEPT { + ALLOW { + Actors: Analyst + Resources + Actions + } + }; diff --git a/src/test/kotlin/helpers/Helpers.kt b/src/test/kotlin/helpers/Helpers.kt index 039cfb9..e8aaae5 100644 --- a/src/test/kotlin/helpers/Helpers.kt +++ b/src/test/kotlin/helpers/Helpers.kt @@ -3,6 +3,7 @@ package helpers import java.io.File import hapi.* +import tasks.YAMLGenerator import utils.* fun irFromFile(file: String) : IR = @@ -19,4 +20,22 @@ fun irFromString(source: String) : IR = val datamap = evalDataMap(source, "") val ast = evalIR(source, "", datamap) as IRNode ast.ir - } \ No newline at end of file + } + +/* Generates YAML translation of Hapi program from "file" + * Returns the resulting translation's file path + */ +fun yamlFromFile(file: String) : String = + File(file).let { + val root = getDirName(file) + val source = it.readText() + val datamap = evalDataMap(source, root) + val ast = evalIR(source, root, datamap) as IRNode + + val outputFile = changeExtension(file, "yaml") + + val yamlGenerator = YAMLGenerator() + yamlGenerator.generate(ast.ir, datamap, outputFile) + + outputFile + } diff --git a/src/test/kotlin/unit/tasks/YAMLTest.kt b/src/test/kotlin/unit/tasks/YAMLTest.kt new file mode 100644 index 0000000..0218318 --- /dev/null +++ b/src/test/kotlin/unit/tasks/YAMLTest.kt @@ -0,0 +1,58 @@ +import kotlin.test.* +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +import java.io.File + +import helpers.* +import utils.DataMapOrderError + +class YAMLTest { + + @Test + @DisplayName("Should generate the correct YAML") + fun shouldGenerateCorrectYAML() { + val hapiFile = "src/test/fixtures/YAML/Main.hp" + val outputFile = File(yamlFromFile(hapiFile)) + + val expectedFile = "src/test/fixtures/YAML/Expected.yaml" + val expectedOutput = File(expectedFile).readText() + + assertThat(outputFile.readText()).isEqualTo(expectedOutput) + + outputFile.delete() + } + + @Test + @DisplayName("Invalid DataMap names for YAML") + fun invalidDataMapWrongNames() { + val hapiFile = "src/test/fixtures/YAML/WrongNames.hp" + + val error = assertFailsWith { + yamlFromFile(hapiFile) + } + + val expectedMessage = + "Expected data statements for [Actors, Actions, Resources]," + + " got [Actors, Actions, Resource]" + + assertThat(error.message).isEqualTo(expectedMessage) + } + + @Test + @DisplayName("Invalid DataMap order for YAML") + fun invalidDataMapWrongOrder() { + val hapiFile = "src/test/fixtures/YAML/WrongOrder.hp" + + val error = assertFailsWith { + yamlFromFile(hapiFile) + } + + val expectedMessage = + "Expected data statements for [Actors, Actions, Resources]," + + " got [Actors, Resources, Actions]" + + assertThat(error.message).isEqualTo(expectedMessage) + } +} From 979e5d6f444eb5f048483884c522c08cd98f8c10 Mon Sep 17 00:00:00 2001 From: Yowgf Date: Tue, 16 Mar 2021 18:36:21 -0300 Subject: [PATCH 09/11] Fixing bug of generating HTML The HTML was only being generated if the actions were 'Reads', 'Updates', 'Deletes', which is obviously something not wanted. Also, added the DataMapOrderChecker checks. --- src/main/kotlin/tasks/AllTools.kt | 7 ++-- src/main/kotlin/tasks/MatrixPrinter.kt | 50 +++++++++++++++++--------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/tasks/AllTools.kt b/src/main/kotlin/tasks/AllTools.kt index fea1be5..131b444 100644 --- a/src/main/kotlin/tasks/AllTools.kt +++ b/src/main/kotlin/tasks/AllTools.kt @@ -22,15 +22,18 @@ fun main(args: Array) { val sourceFile = File(filepath) val root = getDirName(filepath) val sourceText = sourceFile.readText() + val datamap = evalDataMap(sourceText, root) + DataMapOrderChecker(datamap) // Check that datamap has right keys val irNode = evalIR(sourceText, root, datamap) as IRNode - val actionsDataMap = datamap.getValue("Actions") val actorsDataMap = datamap.getValue("Actors") + val actionsDataMap = datamap.getValue("Actions") val resourcesDataMap = datamap.getValue("Resources") // matrix creation - val matrix = MatrixPrinter(actorsDataMap.elements(), resourcesDataMap.elements()) + val matrix = MatrixPrinter(actorsDataMap.elements(), actionsDataMap.elements(), + resourcesDataMap.elements()) matrix.populateMatrix(irNode.ir) // generates HTML and JSON diff --git a/src/main/kotlin/tasks/MatrixPrinter.kt b/src/main/kotlin/tasks/MatrixPrinter.kt index fd5abbf..f7d8a05 100644 --- a/src/main/kotlin/tasks/MatrixPrinter.kt +++ b/src/main/kotlin/tasks/MatrixPrinter.kt @@ -36,10 +36,12 @@ import com.google.gson.GsonBuilder * */ class MatrixPrinter { - private val resources: Map - private val indexedResources: Array private val actors: Map private val indexedActors: Array + private val actions: Map + private val indexedActions: Array + private val resources: Map + private val indexedResources: Array private val matrix: Array>> /** @@ -49,28 +51,37 @@ class MatrixPrinter { * @param actors names of the actors * @param resources names of the resources */ - constructor(actors: Set, resources: Set) { - - // associate the resources names with the matrix indexes - var index: Int = 0 - this.resources = resources.associateWith {index++} - indexedResources = Array(resources.size) {""} - for ((key, value) in this.resources) { - indexedResources[value] = key - } + constructor(actors: Set, actions: Set, resources: Set) { // associate the actors names with the matrix indexes - index = 0 + var index: Int = 0 this.actors = actors.associateWith {index++} indexedActors = Array(actors.size) {""} for ((key, value) in this.actors) { indexedActors[value] = key } + // associate the actions names with the matrix indexes + index = 0 + this.actions = actions.associateWith {index++} + indexedActions = Array(actions.size) {""} + for ((key, value) in this.actions) { + indexedActions[value] = key + } + + // associate the resources names with the matrix indexes + index = 0 + this.resources = resources.associateWith {index++} + indexedResources = Array(resources.size) {""} + for ((key, value) in this.resources) { + indexedResources[value] = key + } + // create matrix this.matrix = Array>>(actors.size) { Array>(resources.size) { - mutableMapOf("Reads" to 0, "Updates" to 0, "Deletes" to 0) + // Initially associcate each action with zero + actions.associateWith { 0 } as MutableMap } } } @@ -144,9 +155,10 @@ class MatrixPrinter { for (j in 0..(matrix[i].size)-1) { val cell = matrix[i][j] td { - p {+"Reads: ${cell["Reads"]}"} - p {+"Updates: ${cell["Updates"]}"} - p {+"Deletes: ${cell["Deletes"]}"} + // Format something like "Reads: 0" + indexedActions.forEach { action -> + p {+(action + ": ${cell[action]}")} + } } } } @@ -218,14 +230,18 @@ fun main(args: Array) { val sourceFile = File(filepath) val root = getDirName(filepath) val sourceText = sourceFile.readText() + val datamap = evalDataMap(sourceText, root) + DataMapOrderChecker(datamap) // Check that datamap has right keys val irNode = evalIR(sourceText, root, datamap) as IRNode val actorsDataMap = datamap.getValue("Actors") + val actionsDataMap = datamap.getValue("Actions") val resourcesDataMap = datamap.getValue("Resources") // generate matrix - val matrix = MatrixPrinter(actorsDataMap.elements(), resourcesDataMap.elements()) + val matrix = MatrixPrinter(actorsDataMap.elements(), actionsDataMap.elements(), + resourcesDataMap.elements()) matrix.populateMatrix(irNode.ir) // Generate output files From 1a67a42903acfe41b29fe8ecbe3b4c45978f37f7 Mon Sep 17 00:00:00 2001 From: Yowgf Date: Thu, 18 Mar 2021 18:59:44 -0300 Subject: [PATCH 10/11] Access matrix only displays atoms --- src/main/kotlin/tasks/AllTools.kt | 3 +-- src/main/kotlin/tasks/MatrixPrinter.kt | 17 ++++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/tasks/AllTools.kt b/src/main/kotlin/tasks/AllTools.kt index 131b444..8b02673 100644 --- a/src/main/kotlin/tasks/AllTools.kt +++ b/src/main/kotlin/tasks/AllTools.kt @@ -32,8 +32,7 @@ fun main(args: Array) { val resourcesDataMap = datamap.getValue("Resources") // matrix creation - val matrix = MatrixPrinter(actorsDataMap.elements(), actionsDataMap.elements(), - resourcesDataMap.elements()) + val matrix = MatrixPrinter(datamap) matrix.populateMatrix(irNode.ir) // generates HTML and JSON diff --git a/src/main/kotlin/tasks/MatrixPrinter.kt b/src/main/kotlin/tasks/MatrixPrinter.kt index f7d8a05..0eacfb3 100644 --- a/src/main/kotlin/tasks/MatrixPrinter.kt +++ b/src/main/kotlin/tasks/MatrixPrinter.kt @@ -51,7 +51,15 @@ class MatrixPrinter { * @param actors names of the actors * @param resources names of the resources */ - constructor(actors: Set, actions: Set, resources: Set) { + constructor(datamap: DataMap) { + DataMapOrderChecker(datamap) // Check that datamap has correct keys + + // Only consider the atoms + fun getDMAtoms(latticeName: String) = + datamap[latticeName]!!.atoms(datamap[latticeName]!!.TOP).unwrap().sorted() + val actors = getDMAtoms("Actors") + val actions = getDMAtoms("Actions") + val resources = getDMAtoms("Resources") // associate the actors names with the matrix indexes var index: Int = 0 @@ -235,13 +243,8 @@ fun main(args: Array) { DataMapOrderChecker(datamap) // Check that datamap has right keys val irNode = evalIR(sourceText, root, datamap) as IRNode - val actorsDataMap = datamap.getValue("Actors") - val actionsDataMap = datamap.getValue("Actions") - val resourcesDataMap = datamap.getValue("Resources") - // generate matrix - val matrix = MatrixPrinter(actorsDataMap.elements(), actionsDataMap.elements(), - resourcesDataMap.elements()) + val matrix = MatrixPrinter(datamap) matrix.populateMatrix(irNode.ir) // Generate output files From 0261be2a2b016b0fbe9489cd6ca570533a437ebe Mon Sep 17 00:00:00 2001 From: Yowgf Date: Wed, 12 May 2021 17:45:53 -0500 Subject: [PATCH 11/11] Removed HTML generation --- build.gradle.kts | 6 +- src/main/kotlin/tasks/AllTools.kt | 6 +- src/main/kotlin/tasks/MatrixPrinter.kt | 90 ++------------------------ 3 files changed, 7 insertions(+), 95 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5131a05..1ab5896 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,10 +32,6 @@ dependencies { // Use the Kotlin JUnit integration. testImplementation("org.jetbrains.kotlin:kotlin-test-junit") - // Use HEML manipulator for matrix printer - implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.1") - implementation("org.jetbrains.kotlinx:kotlinx-html-js:0.7.1") - implementation("com.google.code.gson:gson:2.8.5") antlr("org.antlr:antlr4:4.8") @@ -146,4 +142,4 @@ task("build-all-tools", type = Jar::class) { configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) } }) baseName = project.name -} \ No newline at end of file +} diff --git a/src/main/kotlin/tasks/AllTools.kt b/src/main/kotlin/tasks/AllTools.kt index 8b02673..5a53034 100644 --- a/src/main/kotlin/tasks/AllTools.kt +++ b/src/main/kotlin/tasks/AllTools.kt @@ -35,10 +35,8 @@ fun main(args: Array) { val matrix = MatrixPrinter(datamap) matrix.populateMatrix(irNode.ir) - // generates HTML and JSON - var matrixOutputFile = changeExtension(filepath, "html") - matrix.generateHtmlFile(matrixOutputFile) - matrixOutputFile = changeExtension(filepath, "json") + // generates JSON + val matrixOutputFile = changeExtension(filepath, "json") matrix.generateJsonFile(matrixOutputFile) // generates .dot files diff --git a/src/main/kotlin/tasks/MatrixPrinter.kt b/src/main/kotlin/tasks/MatrixPrinter.kt index 0eacfb3..86317c4 100644 --- a/src/main/kotlin/tasks/MatrixPrinter.kt +++ b/src/main/kotlin/tasks/MatrixPrinter.kt @@ -8,9 +8,6 @@ import java.io.FileOutputStream import java.io.File import java.io.FileWriter -import kotlinx.html.* -import kotlinx.html.dom.* - import javax.xml.transform.TransformerFactory import javax.xml.transform.OutputKeys import javax.xml.parsers.DocumentBuilderFactory @@ -23,16 +20,15 @@ import com.google.gson.GsonBuilder * The class responsible for the matrix representation of a Hapi policy. *

* It implements the Kotlin matrix representation, as well as routines to - * generate its respective serialized formats, namely HTML and JSON. + * generate its JSON version. * Usage example: *

  *     // generate matrix
  *     val matrix = MatrixPrinter(actorsDataMap.elements(),
  *                                resourcesDataMap.elements())
  *     matrix.populateMatrix(irNode.ir)
- *     // HTML and JSON
+ *     // Generate JSON
  *     matrix.generateHtmlFile("Output.html")
- *     matrix.generateJsonFile("Output.json")
  * 
*/ class MatrixPrinter { @@ -112,80 +108,6 @@ class MatrixPrinter { } } - /** - * Generates and fills the target HTML serialized file with the properly - * formatted contents of the Hapi matrix. - *

- * Makes use of the Kotlin DSL for HTML - * kotlinx.html - * to easily create the java object. - * @param htmFileName target file - */ - public fun generateHtmlFile(htmFileName: String) { - val document = DocumentBuilderFactory.newInstance(). - newDocumentBuilder().newDocument() - - //kotlinx.html notation to generate a html page - val html = document.create.html { - head { - title("Lattice Matrix") - style { - unsafe { - raw( - """ - table, th, td { - border: 1px solid black; - border-collapse: collapse; - } - th, td { - padding: 8px 4px; - text-align: left; - } - p { - margin: 4px 0; - } - """ - ) - } - } - } - body { - table { - tr { - th {+" "} - for (resource_name in indexedResources) { - th {+resource_name} - } - } - for (i in 0..(matrix.size)-1) { - tr { - th {+indexedActors[i]} - for (j in 0..(matrix[i].size)-1) { - val cell = matrix[i][j] - td { - // Format something like "Reads: 0" - indexedActions.forEach { action -> - p {+(action + ": ${cell[action]}")} - } - } - } - } - } - } - } - } - - with(TransformerFactory.newInstance().newTransformer()) { - setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no") - setOutputProperty(OutputKeys.METHOD, "xml") - setOutputProperty(OutputKeys.INDENT, "yes") - setOutputProperty(OutputKeys.ENCODING, "UTF-8") - setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4") - transform(DOMSource(html), - StreamResult(OutputStreamWriter(FileOutputStream(htmFileName), "UTF-8"))) - } - } - /** * Generates and fills the target JSON serialized file with the properly * formatted contents of the Hapi matrix. @@ -222,7 +144,7 @@ class MatrixPrinter { } /** - * Builds the matrix and generates both HTML and JSON output files. + * Builds the matrix and generates JSON output file. * This is called by the gradle task "matrix". * * @param args the Hapi policy file name. The output serialized files shall have @@ -247,10 +169,6 @@ fun main(args: Array) { val matrix = MatrixPrinter(datamap) matrix.populateMatrix(irNode.ir) - // Generate output files - var matrixOutputFile = changeExtension(filepath, "html") - matrix.generateHtmlFile(matrixOutputFile) - - matrixOutputFile = changeExtension(filepath, "json") + val matrixOutputFile = changeExtension(filepath, "json") matrix.generateJsonFile(matrixOutputFile); }