
com.innovenso.townplanner.io.concepts.ConceptExcelIO.scala Maven / Gradle / Ivy
package com.innovenso.townplanner.io.concepts
import com.innovenso.townplanner.io.concepts.ExcelFields._
import com.innovenso.townplanner.model._
import com.innovenso.townplanner.model.concepts.properties.{
API,
ApiScope,
ApiStyle,
ArchitectureVerdict,
AuthenticationType,
Criticality,
DDoSProtection,
DataClassification,
Description,
RateLimiting
}
import com.innovenso.townplanner.model.language.Concept
import com.innovenso.townplanner.model.meta.{Key, SortKey}
import org.apache.poi.ss.usermodel.{Row, Sheet}
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.util.UUID
trait ConceptExcelIO[ConceptType <: Concept] extends WorksheetIO {
def conceptClass: Class[ConceptType]
def sheetName: String
def headerLabels: List[String]
private def allHeaderLabels: List[String] =
List(KEY) ::: headerLabels ::: List(SORT_KEY)
def cellValues(concept: ConceptType): List[String]
private def allCellValues(
concept: ConceptType
): List[String] = List(concept.key.value) ::: cellValues(concept) ::: List(
concept.sortKey.value.getOrElse("")
)
override def worksheet(
townPlan: TownPlan,
workbook: XSSFWorkbook
): Option[Sheet] = for {
sheet <- prepareSheet(workbook, sheetName)
header <- prepareHeader(
sheet,
allHeaderLabels
)
rows <- conceptRows(sheet, townPlan)
} yield sheet
private def conceptRows(sheet: Sheet, townPlan: TownPlan): Option[List[Row]] =
if (townPlan.components(conceptClass).isEmpty) None
else
Some(
townPlan
.components(conceptClass)
.zipWithIndex
.flatMap(tuple => row(sheet, tuple._2 + 1, tuple._1))
)
private def row(
sheet: Sheet,
index: Int,
concept: ConceptType
): Option[Row] =
Option(sheet.getRow(index))
.orElse(Some(sheet.createRow(index)))
.flatMap(r => cells(r, concept))
private def cells(row: Row, concept: ConceptType): Option[Row] = {
allCellValues(concept).zipWithIndex.foreach(value =>
cell(row, value._2, value._1)
)
Some(row)
}
private def inputWorksheet(workbook: XSSFWorkbook): Option[Sheet] =
Option(workbook.getSheet(sheetName))
private def concepts(
worksheet: Option[Sheet],
enterpriseArchitecture: EnterpriseArchitecture
): Unit =
listOfRows(worksheet).foreach(row =>
try {
concept(values(worksheet, Some(row)), enterpriseArchitecture)
} catch {
case e: Throwable =>
println(
s"Could not import worksheet ${worksheet
.map(_.getSheetName)
.getOrElse("-")}, row ${row.getRowNum}: ${e.getMessage}"
)
}
)
def concept(
props: ConceptProperties,
enterpriseArchitecture: EnterpriseArchitecture
): Unit
def values(worksheet: Option[Sheet], row: Option[Row]): ConceptProperties =
ConceptProperties(
allHeaderLabels
.map(hl => (hl, columnIndex(worksheet, hl)))
.map(tuple =>
(tuple._1, getCellValue(worksheet, row, tuple._2).getOrElse(""))
)
.toMap
)
override def read(
enterpriseArchitecture: EnterpriseArchitecture,
workbook: XSSFWorkbook
): Unit =
inputWorksheet(workbook)
.foreach(sheet => concepts(Some(sheet), enterpriseArchitecture))
}
case class ConceptProperties(cellValues: Map[String, String]) {
def apply(key: String): String = cellValues.getOrElse(key, "")
def bool(key: String): Boolean = apply(key) match {
case "yes" | "true" | "1" | "Yes" | "YES" | "True" | "TRUE" => true
case _ => false
}
def option(key: String): Option[String] = Option(apply(key)) match {
case Some(string) if !string.isBlank => Some(string)
case _ => None
}
def key: Key = Key.fromString(apply(KEY))
def sortKey: SortKey = Option(apply(SORT_KEY)) match {
case Some(string) if !string.isBlank => SortKey(Some(string))
case _ => SortKey.next
}
def sourceKey: Key = Option(apply(SOURCE_KEY))
.filter(_.trim.nonEmpty)
.map(Key.fromString)
.getOrElse(Key.random)
def targetKey: Key = Option(apply(TARGET_KEY))
.filter(_.trim.nonEmpty)
.map(Key.fromString)
.getOrElse(Key.random)
def title: String = apply(TITLE)
def descriptions: List[Description] =
apply(DESCRIPTION).split("\n\n").map(Description).toList
def architectureVerdict: ArchitectureVerdict = ArchitectureVerdict.fromString(
apply(ARCHITECTURE_VERDICT),
Option(apply(ARCHITECTURE_VERDICT_EXPLANATION))
)
def criticality: Criticality = Criticality.fromString(
apply(CRITICALITY),
Option(apply(CRITICALITY_CONSEQUENCES))
)
def dataClassification: DataClassification = DataClassification.fromString(
apply(CLASSIFICATION),
Option(apply(CLASSIFICATION_DESCRIPTION))
)
def api: Option[API] = Option(apply(API_STYLE))
.filter(_.trim.nonEmpty)
.map(apiStyle =>
API(
authentication = AuthenticationType
.fromString(apply(API_AUTH_STYLE), option(API_AUTH_DESCRIPTION)),
style =
ApiStyle.fromString(apply(API_STYLE), option(API_STYLE_DESCRIPTION)),
scope =
ApiScope.fromString(apply(API_SCOPE), option(API_SCOPE_DESCRIPTION)),
ddoSProtection = DDoSProtection.fromString(
apply(DDOS_PROTECTION),
option(DDOS_PROTECTION_DESCRIPTION)
),
rateLimiting = RateLimiting
.fromString(apply(RATE_LIMITING), option(RATE_LIMITING_DESCRIPTION))
)
)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy