Skip to content

Commit

Permalink
Further testing
Browse files Browse the repository at this point in the history
  • Loading branch information
henrietteharmse committed Nov 18, 2023
1 parent 08d7ef3 commit c25478b
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 22 deletions.
Binary file modified docs/SimpleEmployerExample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/uml2semantics.qea
Binary file not shown.
32 changes: 17 additions & 15 deletions src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala
Original file line number Diff line number Diff line change
Expand Up @@ -554,12 +554,9 @@ case class UMLClass(classIdentity: UMLClassIdentity,
case class UMLClassAttributeDefinition(definition: String = "")

sealed trait UMLClassAttributeType

case class UMLXMLDataType(attributeType: SupportedDataType) extends UMLClassAttributeType

case class UMLClassIdentityType(attributeType: UMLClassIdentity) extends UMLClassAttributeType


case class UMLEnumerationIdentityType(attributeType: UMLEnumerationIdentity) extends UMLClassAttributeType
case class CurieBasedUMLClassAttributeType(attributeType: Curie) extends UMLClassAttributeType

//case class UndefinedUMLClassAttributeType() extends UMLClassAttributeType
Expand All @@ -571,20 +568,25 @@ object UMLClassAttributeType:

def apply(s: String): UMLClassAttributeType =
logger.debug(s"s=$s ${Code.source}")
require(UMLClassIdentity.findClassNamedElement(s).nonEmpty || SupportedDataType.unapply(s).nonEmpty
|| Curie.isCurieBasedOnConfiguredPrefix(s) || s.isEmpty,
s"""A class attribute must have a type that is either a class, that has been specified,
require(UMLClassIdentity.findClassNamedElement(s).nonEmpty ||
UMLEnumerationIdentity.findEnumerationNamedElement(s).nonEmpty ||
SupportedDataType.unapply(s).nonEmpty ||
Curie.isCurieBasedOnConfiguredPrefix(s) ||
s.isEmpty,
s"""A class attribute must have a type that is either a class or enumeration, that has been specified,
or an XML data type or an curie based on a known prefix. Prefixes are specified using the -x option when running uml2semantics.
"$s" is not recognised as either a class or an XML data type.""")
"$s" is not recognised as either a class or an enumeration or an XML data type.""")
UMLClassIdentity.findClassNamedElement(s) match
case Some(classNamedElement) => UMLClassIdentityType(classNamedElement)
case None => SupportedDataType.unapply(s) match
case Some(x) => UMLXMLDataType(x)
case None =>
val curieOption: Option[Curie] = Curie.unapply(s)
curieOption match
case Some(curie) => CurieBasedUMLClassAttributeType(curie)
case None => UndefinedUMLClassAttributeType
case None => UMLEnumerationIdentity.findEnumerationNamedElement(s) match
case Some(enumerationNamedElement) => UMLEnumerationIdentityType(enumerationNamedElement)
case None => SupportedDataType.unapply(s) match
case Some(x) => UMLXMLDataType(x)
case None =>
val curieOption: Option[Curie] = Curie.unapply(s)
curieOption match
case Some(curie) => CurieBasedUMLClassAttributeType(curie)
case None => UndefinedUMLClassAttributeType

def unapply(s: String): Option[UMLClassAttributeType] =
logger.debug(s"s=$s ${Code.source}")
Expand Down
52 changes: 52 additions & 0 deletions src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram):
owlProperty = createOWLDataProperty(umlClassAttribute, errorMessages, domain, attributeType)
case UMLClassIdentityType(attributeType) =>
owlProperty = createOWLObjectProperty(umlClassAttribute, errorMessages, domain, attributeType)
case UMLEnumerationIdentityType(attributeType) =>
owlProperty = createOWLObjectProperty(umlClassAttribute, errorMessages, domain, attributeType)
case CurieBasedUMLClassAttributeType(attributeType) =>
owlProperty = createOWLObjectPropertyBasedOnConfiguredPrefix(umlClassAttribute, errorMessages, domain, attributeType)
case UndefinedUMLClassAttributeType =>
Expand Down Expand Up @@ -157,6 +159,56 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram):
case UMLMultiplicity(UMLInfiniteCardinality(_), UMLInfiniteCardinality(_)) =>
objectProperty

private def createOWLObjectProperty(umlClassAttribute: UMLClassAttribute,
errorMessages: mutable.Seq[String],
domain: OWLClass,
umlEnumerationIdentity: UMLEnumerationIdentity): OWLObjectProperty =
logger.debug(s"createOWLObjectProperty: umlClassAttribute=$umlClassAttribute, errorMessages = $errorMessages, " +
s"domain=$domain, umlEnumerationIdentity=$umlEnumerationIdentity ${Code.source}")
val objectProperty = dataFactory.getOWLObjectProperty(umlClassAttribute.attributeIdentity.attributeIRI.iri)
val domainChangeApplied = manager.addAxiom(ontology, dataFactory.getOWLObjectPropertyDomainAxiom(objectProperty, domain))
if domainChangeApplied != SUCCESSFULLY then
errorMessages :+ s"Domain axiom for object property ${objectProperty.getIRI} could not be added for " +
s"${umlClassAttribute.attributeIdentity.attributeIRI.iri}"
val rangeChangeApplied = manager.addAxiom(ontology, dataFactory.getOWLObjectPropertyRangeAxiom(objectProperty,
dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
if rangeChangeApplied != SUCCESSFULLY then
errorMessages :+ s"Range axiom for data property ${objectProperty.getIRI} could not be added for " +
s"${umlClassAttribute.attributeIdentity.attributeIRI.iri}"
umlClassAttribute.multiplicity match
case UMLMultiplicity(UMLNonNegativeCardinality(minCardinality), UMLNonNegativeCardinality(maxCardinality)) =>
logger.trace(s"minCardinality=$minCardinality ${Code.source}")
val axiom =
if minCardinality == maxCardinality && minCardinality != 0 then
dataFactory.getOWLSubClassOfAxiom(domain, dataFactory.getOWLObjectExactCardinality(maxCardinality, objectProperty,
dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
else if minCardinality > 0 then
dataFactory.getOWLSubClassOfAxiom(domain,
dataFactory.getOWLObjectIntersectionOf(
dataFactory.getOWLObjectMinCardinality(minCardinality, objectProperty,
dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)),
dataFactory.getOWLObjectMaxCardinality(maxCardinality, objectProperty,
dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri))))
else
dataFactory.getOWLSubClassOfAxiom(domain, dataFactory.getOWLObjectMaxCardinality(maxCardinality, objectProperty,
dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
if manager.addAxiom(ontology, axiom) != SUCCESSFULLY then
errorMessages :+ s"Could not add subclass axiom representing cardinalities [$minCardinality, $maxCardinality] for " +
s"${umlClassAttribute.attributeIdentity.attributeLabel}"
case UMLMultiplicity(UMLNonNegativeCardinality(minCardinality), UMLInfiniteCardinality(_)) =>
if minCardinality > 0 then
val axiom = dataFactory.getOWLSubClassOfAxiom(domain,
dataFactory.getOWLObjectMinCardinality(minCardinality, objectProperty,
dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
if manager.addAxiom(ontology, axiom) != SUCCESSFULLY then
errorMessages :+ s"Could not add subclass axiom representing cardinalities for [$minCardinality, *]" +
s"${umlClassAttribute.attributeIdentity.attributeLabel}"
case UMLMultiplicity(UMLInfiniteCardinality(_), UMLNonNegativeCardinality(maxCardinality)) =>
errorMessages :+ s"Multiplicity error found with multiplicity = [*, $maxCardinality] for attribute = " +
s"${umlClassAttribute.attributeIdentity.attributeLabel}."
case UMLMultiplicity(UMLInfiniteCardinality(_), UMLInfiniteCardinality(_)) =>
objectProperty

private def createOWLObjectProperty(umlClassAttribute: UMLClassAttribute,
errorMessages: mutable.Seq[String],
domain: OWLClass): OWLObjectProperty =
Expand Down
16 changes: 11 additions & 5 deletions src/main/scala/org/uml2semantics/reader/TSVReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ def parseAttributes(maybeTsvFile: Option[File], ontologyPrefix: PrefixNamespace)
logger.trace(s"m = $m")

val classNamedElement = UMLClassIdentity.findClassNamedElement(m(ClassAttributesHeader.ClassName.toString))
val enumerationNamedElement = UMLEnumerationIdentity.findEnumerationNamedElement(m(ClassAttributesHeader.ClassName.toString))
logger.trace(s"classNamedElement = $classNamedElement")
if classNamedElement.isDefined then
if classNamedElement.isDefined || enumerationNamedElement.isDefined then
logger.trace(s"mClassOrPrimitiveType.toString = {${m(ClassOrPrimitiveType.toString)}}")
val curieOption: Option[Curie] = if m(Curie.toString).contains(":") then
Some(org.uml2semantics.model.Curie(m(Curie.toString)))
Expand Down Expand Up @@ -191,14 +192,19 @@ def parseEnumerationValues(maybeTsvFile: Option[File], ontologyPrefix: PrefixNam
end parseEnumerationValues

def parseUMLClassDiagram(input: InputParameters): UMLClassDiagram =
var umlClasses = parseClasses(input.classesTsv, PrefixNamespace(input.ontologyPrefix))
var umlEnumerations = parseEnumerations(input.enumerationsTsv, PrefixNamespace(input.ontologyPrefix))
var umlAttributes = parseAttributes(input.attributesTsv, PrefixNamespace(input.ontologyPrefix))
var umlEnumerationValues = parseEnumerationValues(input.enumerationValuesTsv, PrefixNamespace(input.ontologyPrefix))

UMLClassDiagram(
input.owlOntologyFile.get,
OntologyIRI(input.ontologyIRI),
PrefixNamespace(input.ontologyPrefix),
parseClasses(input.classesTsv, PrefixNamespace(input.ontologyPrefix)),
parseAttributes(input.attributesTsv, PrefixNamespace(input.ontologyPrefix)),
parseEnumerations(input.enumerationsTsv, PrefixNamespace(input.ontologyPrefix)),
parseEnumerationValues(input.enumerationValuesTsv, PrefixNamespace(input.ontologyPrefix)))
umlClasses,
umlAttributes,
umlEnumerations,
umlEnumerationValues)



5 changes: 4 additions & 1 deletion src/test/resources/Employer - Attributes.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ Person name xsd:string
Person surname xsd:string
Person dateOfBirth xsd:dateTime
Employee employedBy Employer 1 1
Employer employes Employee 1 *
Employee renumeration Renumeration 1 1
Employer employes Employee 1 *
Renumeration rate xsd:decimal 1 1
Renumeration paymentSchedule PaymentSchedule 1 1
3 changes: 2 additions & 1 deletion src/test/resources/Employer - Classes.tsv
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Curie Name Definition ParentNames
Person
Employee Person
Employer Person
Employer Person
Renumeration
64 changes: 64 additions & 0 deletions src/test/resources/employer.rdf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@



<!-- http://uml2semantics.org/examples/employer#Employee/renumeration -->


<owl:ObjectProperty rdf:about="http://uml2semantics.org/examples/employer#Employee/renumeration">
<rdfs:domain rdf:resource="http://uml2semantics.org/examples/employer#Employee"/>
<rdfs:range rdf:resource="http://uml2semantics.org/examples/employer#Renumeration"/>
<rdfs:label>renumeration</rdfs:label>
</owl:ObjectProperty>



<!-- http://uml2semantics.org/examples/employer#Employer/employes -->


Expand All @@ -44,6 +55,17 @@



<!-- http://uml2semantics.org/examples/employer#Renumeration/paymentSchedule -->


<owl:ObjectProperty rdf:about="http://uml2semantics.org/examples/employer#Renumeration/paymentSchedule">
<rdfs:domain rdf:resource="http://uml2semantics.org/examples/employer#Renumeration"/>
<rdfs:range rdf:resource="http://uml2semantics.org/examples/employer#SalarySchedule"/>
<rdfs:label>paymentSchedule</rdfs:label>
</owl:ObjectProperty>



<!--
///////////////////////////////////////////////////////////////////////////////////////
//
Expand Down Expand Up @@ -89,6 +111,17 @@



<!-- http://uml2semantics.org/examples/employer#Renumeration/rate -->


<owl:DatatypeProperty rdf:about="http://uml2semantics.org/examples/employer#Renumeration/rate">
<rdfs:domain rdf:resource="http://uml2semantics.org/examples/employer#Renumeration"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#decimal"/>
<rdfs:label>rate</rdfs:label>
</owl:DatatypeProperty>



<!--
///////////////////////////////////////////////////////////////////////////////////////
//
Expand All @@ -113,6 +146,13 @@
<owl:onClass rdf:resource="http://uml2semantics.org/examples/employer#Employer"/>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="http://uml2semantics.org/examples/employer#Employee/renumeration"/>
<owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:qualifiedCardinality>
<owl:onClass rdf:resource="http://uml2semantics.org/examples/employer#Renumeration"/>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:label>Employee</rdfs:label>
</owl:Class>

Expand Down Expand Up @@ -166,6 +206,30 @@



<!-- http://uml2semantics.org/examples/employer#Renumeration -->


<owl:Class rdf:about="http://uml2semantics.org/examples/employer#Renumeration">
<rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="http://uml2semantics.org/examples/employer#Renumeration/paymentSchedule"/>
<owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:qualifiedCardinality>
<owl:onClass rdf:resource="http://uml2semantics.org/examples/employer#SalarySchedule"/>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="http://uml2semantics.org/examples/employer#Renumeration/rate"/>
<owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:qualifiedCardinality>
<owl:onDataRange rdf:resource="http://www.w3.org/2001/XMLSchema#decimal"/>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:label>Renumeration</rdfs:label>
</owl:Class>



<!-- http://uml2semantics.org/examples/employer#SalarySchedule -->


Expand Down

0 comments on commit c25478b

Please sign in to comment.