diff --git a/src/main/scala/org/uml2semantics/Input.scala b/src/main/scala/org/uml2semantics/Input.scala index a8577e7..eb3681d 100644 --- a/src/main/scala/org/uml2semantics/Input.scala +++ b/src/main/scala/org/uml2semantics/Input.scala @@ -7,7 +7,7 @@ import java.io.File case class InputParameters(classesTsv: Option[File] = None, attributesTsv: Option[File] = None, enumerationsTsv: Option[File] = None, - enumerationsValuesTsv: Option[File] = None, + enumerationValuesTsv: Option[File] = None, owlOntologyFile: Option[File] = None, ontologyIRI: String = "https://uml2semantics.com/ontology", ontologyPrefix: String = "uml2ont:https://uml2semantics.com/ontology/", diff --git a/src/main/scala/org/uml2semantics/Main.scala b/src/main/scala/org/uml2semantics/Main.scala index b01a033..698e9c7 100644 --- a/src/main/scala/org/uml2semantics/Main.scala +++ b/src/main/scala/org/uml2semantics/Main.scala @@ -44,7 +44,7 @@ val argParser = .text("A TSV file containing UML enumerations"), opt[Option[File]]('n', "enumeration values") .valueName("") - .action((a, c) => c.copy(enumerationsValuesTsv = a)) + .action((a, c) => c.copy(enumerationValuesTsv = a)) .validate(o => if (o.exists(f => f.exists()) || o.isEmpty) success else failure(s"The file \"${o.get}\" does not exist.") diff --git a/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala b/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala index 1e26198..081d4fd 100644 --- a/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala +++ b/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala @@ -6,6 +6,7 @@ import org.uml2semantics.model.UMLCardinality.{>=, logger} import sourcecode.Text import java.io.File +import scala.:+ import scala.annotation.{tailrec, targetName} import scala.collection.mutable @@ -111,11 +112,11 @@ case class UMLClassAttributeIdentity(classNamedElement: UMLClassNamedElement, object UMLClassAttributeIdentity: private val logger = Logger[this.type] - private val attributeIdentityByName: mutable.HashMap[UMLClassAttributeName, UMLClassAttributeIdentity] = + private var attributeIdentityByName: mutable.HashMap[UMLClassAttributeName, UMLClassAttributeIdentity] = mutable.HashMap[UMLClassAttributeName, UMLClassAttributeIdentity]() - private val attributeIdentityByIRI: mutable.HashMap[UMLClassAttributeIRI, UMLClassAttributeIdentity] = + private var attributeIdentityByIRI: mutable.HashMap[UMLClassAttributeIRI, UMLClassAttributeIdentity] = mutable.HashMap[UMLClassAttributeIRI, UMLClassAttributeIdentity]() - private val attributeIdentityByCurie: mutable.HashMap[UMLClassAttributeCurie, UMLClassAttributeIdentity] = + private var attributeIdentityByCurie: mutable.HashMap[UMLClassAttributeCurie, UMLClassAttributeIdentity] = mutable.HashMap[UMLClassAttributeCurie, UMLClassAttributeIdentity]() def apply(classNamedElement: UMLClassNamedElement, @@ -175,11 +176,11 @@ case class UMLEnumerationValueIdentity(enumerationNamedElement: UMLEnumerationNa object UMLEnumerationValueIdentity: private val logger = Logger[this.type] - private val valueIdentityByName: mutable.HashMap[UMLEnumerationValueName, UMLEnumerationValueIdentity] = + private var valueIdentityByName: mutable.HashMap[UMLEnumerationValueName, UMLEnumerationValueIdentity] = mutable.HashMap[UMLEnumerationValueName, UMLEnumerationValueIdentity]() - private val valueIdentityByIRI: mutable.HashMap[UMLEnumerationValueIRI, UMLEnumerationValueIdentity] = + private var valueIdentityByIRI: mutable.HashMap[UMLEnumerationValueIRI, UMLEnumerationValueIdentity] = mutable.HashMap[UMLEnumerationValueIRI, UMLEnumerationValueIdentity]() - private val valueIdentityByCurie: mutable.HashMap[UMLEnumerationValueCurie, UMLEnumerationValueIdentity] = + private var valueIdentityByCurie: mutable.HashMap[UMLEnumerationValueCurie, UMLEnumerationValueIdentity] = mutable.HashMap[UMLEnumerationValueCurie, UMLEnumerationValueIdentity]() def apply(enumerationNamedElement: UMLEnumerationNamedElement, @@ -402,9 +403,9 @@ case class UMLClassIdentity(className: UMLClassName, object UMLClassIdentity: private val logger = Logger[this.type] - private val classIdentityByName: mutable.HashMap[UMLClassName, UMLClassIdentity] = mutable.HashMap[UMLClassName, UMLClassIdentity]() - private val classIdentityByIRI: mutable.HashMap[UMLClassIRI, UMLClassIdentity] = mutable.HashMap[UMLClassIRI, UMLClassIdentity]() - private val classIdentityByCurie: mutable.HashMap[UMLClassCurie, UMLClassIdentity] = mutable.HashMap[UMLClassCurie, UMLClassIdentity]() + private var classIdentityByName: mutable.HashMap[UMLClassName, UMLClassIdentity] = mutable.HashMap[UMLClassName, UMLClassIdentity]() + private var classIdentityByIRI: mutable.HashMap[UMLClassIRI, UMLClassIdentity] = mutable.HashMap[UMLClassIRI, UMLClassIdentity]() + private var classIdentityByCurie: mutable.HashMap[UMLClassCurie, UMLClassIdentity] = mutable.HashMap[UMLClassCurie, UMLClassIdentity]() /** * @@ -481,9 +482,9 @@ case class UMLEnumerationIdentity(enumerationName: UMLEnumerationName, object UMLEnumerationIdentity: private val logger = Logger[this.type] - private val enumerationIdentityByName: mutable.HashMap[UMLEnumerationName, UMLEnumerationIdentity] = mutable.HashMap[UMLEnumerationName, UMLEnumerationIdentity]() - private val enumerationIdentityByIRI: mutable.HashMap[UMLEnumerationIRI, UMLEnumerationIdentity] = mutable.HashMap[UMLEnumerationIRI, UMLEnumerationIdentity]() - private val enumerationIdentityByCurie: mutable.HashMap[UMLEnumerationCurie, UMLEnumerationIdentity] = mutable.HashMap[UMLEnumerationCurie, UMLEnumerationIdentity]() + private var enumerationIdentityByName: mutable.HashMap[UMLEnumerationName, UMLEnumerationIdentity] = mutable.HashMap[UMLEnumerationName, UMLEnumerationIdentity]() + private var enumerationIdentityByIRI: mutable.HashMap[UMLEnumerationIRI, UMLEnumerationIdentity] = mutable.HashMap[UMLEnumerationIRI, UMLEnumerationIdentity]() + private var enumerationIdentityByCurie: mutable.HashMap[UMLEnumerationCurie, UMLEnumerationIdentity] = mutable.HashMap[UMLEnumerationCurie, UMLEnumerationIdentity]() def apply(enumerationName: UMLEnumerationName = UMLEnumerationName(), enumerationCurie: UMLEnumerationCurie = UMLEnumerationCurie(), @@ -609,14 +610,15 @@ case class UMLEnumeration(enumerationIdentity: UMLEnumerationIdentity, object UMLEnumeration: private val logger = Logger[this.type] - private val enumerationsWithEnumerationValues: mutable.HashMap[UMLEnumerationIdentity, mutable.Set[UMLEnumerationValueIdentity]] = + private var enumerationsWithEnumerationValues: mutable.HashMap[UMLEnumerationIdentity, mutable.Set[UMLEnumerationValueIdentity]] = mutable.HashMap[UMLEnumerationIdentity, mutable.Set[UMLEnumerationValueIdentity]]() - def cache(enumerationIdentity: UMLEnumerationIdentity, enumerationValueIdentity: UMLEnumerationValueIdentity): UMLEnumerationIRI = logger.debug(s"enumerationIdentity=$enumerationIdentity, enumerationValueIdentity=$enumerationValueIdentity ${Code.source}") - val enumerationValues: mutable.Set[UMLEnumerationValueIdentity] = + var enumerationValues: mutable.Set[UMLEnumerationValueIdentity] = enumerationsWithEnumerationValues.getOrElse(enumerationIdentity, mutable.HashSet[UMLEnumerationValueIdentity]()) enumerationValues += enumerationValueIdentity + enumerationsWithEnumerationValues.put(enumerationIdentity, enumerationValues) + logger.trace(s"enumerationsWithEnumerationValues.size = ${enumerationsWithEnumerationValues.size}") enumerationIdentity.enumerationIRI def find(enumerationIdentity: UMLEnumerationIdentity): Option[mutable.Set[UMLEnumerationValueIdentity]] = @@ -630,7 +632,7 @@ case class UMLEnumerationValue(valueIdentity: UMLEnumerationValueIdentity, extends UMLClassDiagramElement object UMLEnumerationValue: - private val enumerationValuesByIdentity: mutable.HashMap[UMLEnumerationValueIdentity, UMLEnumerationValue] = + private var enumerationValuesByIdentity: mutable.HashMap[UMLEnumerationValueIdentity, UMLEnumerationValue] = mutable.HashMap[UMLEnumerationValueIdentity, UMLEnumerationValue]() def apply(valueIdentity: UMLEnumerationValueIdentity, diff --git a/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala b/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala index 08bfc7e..53d2823 100644 --- a/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala +++ b/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala @@ -47,11 +47,13 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram): private def createAndAnnotateOWLClass(umlClass: UMLClass, - errorMessages: mutable.Seq[String]): OWLClass = + errorMessages: mutable.Seq[String], + hasParent: Boolean = false): OWLClass = logger.debug(s"createAndAnnotateOWLClass: umlClass=$umlClass, errorMessages=$errorMessages ${Code.source}") val owlClass = dataFactory.getOWLClass(umlClass.classIdentity.classIRI.iri) - if manager.addAxiom(ontology, dataFactory.getOWLSubClassOfAxiom(owlClass, dataFactory.getOWLThing)) != SUCCESSFULLY then - errorMessages :+ s"Could not add axiom ${owlClass.getIRI} subClassOf owl:Thing" + if !hasParent then + if manager.addAxiom(ontology, dataFactory.getOWLSubClassOfAxiom(owlClass, dataFactory.getOWLThing)) != SUCCESSFULLY then + errorMessages :+ s"Could not add axiom ${owlClass.getIRI} subClassOf owl:Thing" createDefinitionAnnotation(owlClass, umlClass.classDefinition.definition, errorMessages) createLabelAnnotation(owlClass, umlClass.classIdentity.classLabel, errorMessages) owlClass @@ -315,11 +317,12 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram): dataProperty - private def createAndAnnotateNamedIndividual(umlEnumerationValue: UMLEnumerationValue, + private def createAndAnnotateNamedIndividual(enumerationIdentity: UMLEnumerationIdentity, + umlEnumerationValue: UMLEnumerationValue, errorMessages: mutable.Seq[String]): OWLNamedIndividual = logger.debug(s"createAndAnnotateNamedIndividual: umlEnumerationValue=$umlEnumerationValue, " + s"errorMessages=$errorMessages ${Code.source}") - val owlClass = dataFactory.getOWLClass(umlEnumerationValue.valueIdentity.valueIRI.iri) + val owlClass = dataFactory.getOWLClass(enumerationIdentity.enumerationIRI.iri) val owlNamedIndividual = dataFactory.getOWLNamedIndividual(umlEnumerationValue.valueIdentity.valueIRI.iri) val axiom = dataFactory.getOWLClassAssertionAxiom(owlClass, owlNamedIndividual) if manager.addAxiom(ontology, axiom) != SUCCESSFULLY then @@ -331,12 +334,12 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram): private def processUMLClasses: mutable.Seq[String] = logger.info("processUMLClasses: Start") - val errorMessages: mutable.Seq[String] = new ArrayBuffer[String]() + var errorMessages: mutable.Seq[String] = new ArrayBuffer[String]() umlClassDiagram.umlClasses.umlClasses.keySet.foreach(id => { val umlClassOption = umlClassDiagram.umlClasses.umlClasses.get(id) if umlClassOption.isDefined then val umlClass = umlClassOption.get - val owlClass = createAndAnnotateOWLClass(umlClass, errorMessages) + val owlClass = createAndAnnotateOWLClass(umlClass, errorMessages, !umlClass.classParentIds.setOfParentNamedElements.isEmpty) if umlClass.classParentIds.setOfParentNamedElements.isEmpty then logger.trace("ParentIds is EMPTY") else @@ -355,7 +358,7 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram): private def processUMLClassAttributes: mutable.Seq[String] = logger.info("processUMLClassAttributes: Start") - val errorMessages: ArrayBuffer[String] = new ArrayBuffer[String]() + var errorMessages: ArrayBuffer[String] = new ArrayBuffer[String]() umlClassDiagram.umlClassAttributes.umlClassAttributes.keySet.foreach(id => { val umlClassAttributeOption = umlClassDiagram.umlClassAttributes.umlClassAttributes.get(id) if umlClassAttributeOption.isDefined then @@ -369,19 +372,20 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram): private def processUMLEnumerations: mutable.Seq[String] = logger.info("processUMLEnumerations: Start") - val errorMessages: mutable.Seq[String] = new ArrayBuffer[String]() + var errorMessages: mutable.Seq[String] = new ArrayBuffer[String]() umlClassDiagram.umlEnumerations.umlEnumerations.keySet.foreach(id => { val umlEnumerationOption = umlClassDiagram.umlEnumerations.umlEnumerations.get(id) - if umlEnumerationOption.isDefined then + if umlEnumerationOption.isDefined then { val umlEnumeration = umlEnumerationOption.get val owlClass = createAndAnnotateOWLClass(umlEnumeration, errorMessages) - if manager.addAxiom(ontology, dataFactory.getOWLSubClassOfAxiom(owlClass, dataFactory.getOWLThing)) != SUCCESSFULLY then - errorMessages :+ s"Could not add axiom ${owlClass.getIRI} subClassOf owl:Thing" val umlEnumerationValueIdentitiesOption = UMLEnumeration.find(umlEnumeration.enumerationIdentity) if umlEnumerationValueIdentitiesOption.isDefined then val individuals: mutable.Set[OWLIndividual] = new mutable.HashSet[OWLIndividual]() umlEnumerationValueIdentitiesOption.get.foreach(v => { - val individual = createAndAnnotateNamedIndividual(UMLEnumerationValue.find(v).get, errorMessages) + val individual = createAndAnnotateNamedIndividual( + umlEnumeration.enumerationIdentity, + UMLEnumerationValue.find(v).get, + errorMessages) individuals += individual }) val owlClassExpression = dataFactory.getOWLObjectOneOf(individuals.asJava) @@ -389,6 +393,7 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram): dataFactory.getOWLEquivalentClassesAxiom(owlClass, owlClassExpression) if (manager.addAxiom(ontology, owlEquivalentClassesAxiom) != SUCCESSFULLY) then errorMessages :+ s"Could not add axiom ${owlClass.getIRI} equivalent to ${owlClassExpression}" + } }) logger.info("processUMLEnumerations: Done") errorMessages @@ -396,7 +401,7 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram): def generateOWL: Either[String, ListBuffer[String]] = logger.info("generateOWL: Start") - val errorMessages = new ListBuffer[String]() + var errorMessages = new ListBuffer[String]() errorMessages.appendAll(processUMLClasses) errorMessages.appendAll(processUMLClassAttributes) errorMessages.appendAll(processUMLEnumerations) diff --git a/src/main/scala/org/uml2semantics/reader/TSVReader.scala b/src/main/scala/org/uml2semantics/reader/TSVReader.scala index d793e04..d040b4e 100644 --- a/src/main/scala/org/uml2semantics/reader/TSVReader.scala +++ b/src/main/scala/org/uml2semantics/reader/TSVReader.scala @@ -28,7 +28,7 @@ def parseClasses(maybeTsvFile: Option[File], ontologyPrefix: PrefixNamespace): U implicit object TsvFormat extends TSVFormat {} val reader = CSVReader.open(maybeTsvFile.get) - val umlClasses = mutable.Set[UMLClass]() + var umlClasses = mutable.Set[UMLClass]() reader.allWithHeaders().foreach(m => { logger.trace(s"m = $m") @@ -70,7 +70,7 @@ def parseAttributes(maybeTsvFile: Option[File], ontologyPrefix: PrefixNamespace) import ClassAttributesHeader.* val logger = Logger("TsvReader: parseAttributes") implicit object TsvFormat extends TSVFormat {} - val umlClassAttributes = mutable.Set[UMLClassAttribute]() + var umlClassAttributes = mutable.Set[UMLClassAttribute]() if maybeTsvFile.isDefined then val reader = CSVReader.open(maybeTsvFile.get) @@ -112,7 +112,7 @@ def parseEnumerations(maybeTsvFile: Option[File], ontologyPrefix: PrefixNamespac logger.info("Start") implicit object TsvFormat extends TSVFormat {} - val umlEnumerations = mutable.Set[UMLEnumeration]() + var umlEnumerations = mutable.Set[UMLEnumeration]() if maybeTsvFile.isDefined then val reader = CSVReader.open(maybeTsvFile.get) @@ -152,7 +152,7 @@ def parseEnumerationValues(maybeTsvFile: Option[File], ontologyPrefix: PrefixNam if maybeTsvFile.isDefined then { val reader = CSVReader.open(maybeTsvFile.get) - val umlEnumerationValues = mutable.Set[UMLEnumerationValue]() + var umlEnumerationValues = mutable.Set[UMLEnumerationValue]() logger.info("Start") reader.allWithHeaders().foreach(m => { @@ -198,7 +198,7 @@ def parseUMLClassDiagram(input: InputParameters): UMLClassDiagram = parseClasses(input.classesTsv, PrefixNamespace(input.ontologyPrefix)), parseAttributes(input.attributesTsv, PrefixNamespace(input.ontologyPrefix)), parseEnumerations(input.enumerationsTsv, PrefixNamespace(input.ontologyPrefix)), - parseEnumerationValues(input.enumerationsValuesTsv, PrefixNamespace(input.ontologyPrefix))) + parseEnumerationValues(input.enumerationValuesTsv, PrefixNamespace(input.ontologyPrefix))) diff --git a/src/test/resources/employer.rdf b/src/test/resources/employer.rdf index 3a6c2d4..d566dd5 100644 --- a/src/test/resources/employer.rdf +++ b/src/test/resources/employer.rdf @@ -106,7 +106,6 @@ - @@ -124,7 +123,6 @@ - @@ -172,10 +170,64 @@ + + + + + + + + + Defines the frequency of payments PaymentSchedule + + + + + + + + + + + + + + + Employee gets paid at the end of each day + Daily + + + + + + + + + + Employee gets paid at the last day of the month + Monthly + + + + + + + + + + Employee gets paid at the end of each week on a Friday + Weekly +