/* * This software is Copyright 2005,2006,2007,2008 Langdale Consultants. * Langdale Consultants can be contacted at: http://www.langdale.com.au */ package au.com.langdale.xmi; import au.com.langdale.kena.OntModel; import au.com.langdale.kena.OntResource; import au.com.langdale.kena.ResIterator; import au.com.langdale.kena.Resource; import com.hp.hpl.jena.graph.FrontsNode; import com.hp.hpl.jena.graph.Node; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; import com.hp.hpl.jena.vocabulary.XSD; /** * Extends the generic XMI interpreter to apply IEC CIM * modelling conventions. * */ public class CIMInterpreter extends UMLInterpreter { public static OntModel interpret(OntModel raw, String baseURI, OntModel annote, boolean usePackageNames) { if( annote != null) raw.add(annote); CIMInterpreter interpreter = new CIMInterpreter(); return interpreter.postProcess(raw, baseURI, usePackageNames); } private OntModel postProcess(OntModel raw, String baseURI, boolean usePackageNames) { setModel(raw); System.out.println("Raw XMI model size: " + getModel().size()); UML.loadOntology(getModel()); pruneIncomplete(); labelRoles(); System.out.println("Stage 1 XMI model size: " + getModel().size()); Translator translator = new Translator(getModel(), baseURI, usePackageNames); translator.run(); setModel(translator.getModel()); System.out.println("Stage 3 XMI model size: " + getModel().size()); propagateComments(); applyStereotypes(); classifyAttributes(); removeUntyped(); // convertToSubClassOf("extensionMSITE"); createOntologyHeader(baseURI); System.out.println("Stage 4 XMI model size: " + getModel().size()); return getModel(); } private void createOntologyHeader(String baseURI) { model.createIndividual(Translator.stripHash(baseURI), OWL.Ontology); model.setNsPrefix("", baseURI); } private void propagateComments() { ResIterator it = model.listObjectProperties(); while( it.hasNext()) { OntResource prop = it.nextResource(); if(prop.getComment() == null) { OntResource node = prop.getResource(UML.roleAOf); if( node == null) node = prop.getResource(UML.roleBOf); if( node != null) { String comment = node.getComment(); if(comment != null) prop.addComment(comment, null); } } } } /** * Find labels for association roles. */ private void labelRoles() { ResIterator it = model.listObjectProperties(); while( it.hasNext()) { OntResource prop = it.nextResource(); if(! reLabel(prop, UML.roleAOf, UML.roleALabel)) reLabel(prop, UML.roleBOf, UML.roleBLabel); } } private boolean reLabel(OntResource prop, FrontsNode roleOf, FrontsNode hasLabel) { OntResource node = prop.getResource(roleOf); if( node != null) { OntResource assoc = node; Node label = assoc.getNode(hasLabel); if( label != null ) { prop.addLabel(label.getLiteralLexicalForm(), XMIModel.LANG); return true; } } return false; } /** * Apply CIM stereotypes and special tags to the model. * * The OWL representation of a UML class is modified in place to match * the stereotype. Recognise stereotypes 'primitive' and 'enumeration'. * */ private void applyStereotypes() { ResIterator jt = model.listSubjectsBuffered(UML.hasStereotype, UML.enumeration); while( jt.hasNext()) { applyEnumerationStereotype(jt.nextResource()); } applyPrimitiveStereotype(UML.cimdatatype, true); applyPrimitiveStereotype(UML.datatype, true); applyPrimitiveStereotype(UML.primitive, true); // in future, change to false applyPrimitiveStereotype(UML.base, true); // in future, change to false applyPrimitiveStereotype(UML.union, false); ResIterator lt = model.listSubjectsBuffered(UML.hasStereotype, UML.extendedBy); while( lt.hasNext()) { convertAssocToSubClassOf(lt.nextResource()); } } private void applyPrimitiveStereotype(Resource stereo, boolean interpret_value) { ResIterator gt = model.listSubjectsBuffered(UML.hasStereotype, stereo); while( gt.hasNext()) { applyPrimitiveStereotype(gt.nextResource(), interpret_value); } } /** * Covert primitive or union stereotyped class as a datatype. */ private void applyPrimitiveStereotype(OntResource clss, boolean interpret_value) { OntResource truetype = null; String units = null; String multiplier = null; // strip the classes properties, record the value and units information ResIterator it = model.listSubjectsBuffered(RDFS.domain, clss); while(it.hasNext()) { OntResource m = it.nextResource(); if( interpret_value ) { String name = m.getLabel(); if(name != null) { // this is a CIM-style annotation to indicate the primitive datatype if( name.equals("value")) truetype = m.getResource(RDFS.range); if( name.equals("unit") || name.equals("units")) units = m.getString(UML.hasInitialValue); if( name.equals("multiplier")) multiplier = m.getString(UML.hasInitialValue); } } // remove spurious property attached to datatype m.removeProperties(); } // for XML Schema datatypes remove all definitions if( clss.getNameSpace().equals(XSD.getURI())){ clss.removeProperties(); } // for defined datatypes, establish an RDFS datatype else { clss.removeAll(RDF.type); clss.addProperty(RDF.type, RDFS.Datatype); if( truetype != null && ! clss.equals(truetype)) clss.addProperty( OWL.equivalentClass, truetype ); if( units != null ) clss.addProperty( UML.hasUnits, units); if( multiplier != null ) clss.addProperty( UML.hasMultiplier, multiplier); } } /** * Convert enumeration stereotyped class and attributes to * a class and its individuals. * * The properties of the class are re-interpreted as * members of the enumeration. Note that OWL EnumeratedClass * is not used here because that would create a closed enumeration. */ private void applyEnumerationStereotype(OntResource clss) { clss.removeAll(RDF.type); clss.addProperty(RDF.type, OWL.Class); // some UML models have inconsistent stereotypes model.remove(clss, UML.hasStereotype, UML.datatype); model.remove(clss, UML.hasStereotype, UML.cimdatatype); model.remove(clss, UML.hasStereotype, UML.base); model.remove(clss, UML.hasStereotype, UML.primitive); ResIterator it = model.listSubjectsBuffered(RDFS.domain, clss); while(it.hasNext()) { OntResource m = it.nextResource(); if( m.hasProperty(UML.hasStereotype, UML.attribute)) { m.removeAll(RDF.type); m.removeAll(RDFS.range); m.removeAll(RDFS.domain); m.removeAll(UML.hasStereotype); m.addProperty(RDF.type, clss); } } } private void convertAssocToSubClassOf(OntResource assoc) { OntResource prop = assoc.getSubject(UML.roleBOf); if( prop != null ) convertPropToSubClassOf(prop); } private void convertPropToSubClassOf(OntResource prop) { OntResource range = prop.getRange(); OntResource domain = prop.getDomain(); if( range != null && domain != null) { OntResource inv = prop.getInverseOf(); prop.remove(); if( model.contains(domain, UML.hasStereotype, UML.extension)) range.addSuperClass(domain); else if( model.contains(range, UML.hasStereotype, UML.extension)) domain.addSuperClass(range); else return; if( inv != null) inv.remove(); } } }